summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile41
-rw-r--r--usr/src/lib/Makefile.astmsg4
-rw-r--r--usr/src/lib/Makefile.lib32
-rw-r--r--usr/src/lib/Makefile.targ8
-rw-r--r--usr/src/lib/Makefile.usdt28
-rw-r--r--usr/src/lib/brand/Makefile3
-rw-r--r--usr/src/lib/brand/lx/Makefile55
-rw-r--r--usr/src/lib/brand/lx/Makefile.lx34
-rw-r--r--usr/src/lib/brand/lx/librtld_db/Makefile54
-rw-r--r--usr/src/lib/brand/lx/librtld_db/Makefile.com83
-rw-r--r--usr/src/lib/brand/lx/librtld_db/amd64/Makefile38
-rw-r--r--usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers44
-rw-r--r--usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c852
-rw-r--r--usr/src/lib/brand/lx/librtld_db/common/mapfile-vers58
-rw-r--r--usr/src/lib/brand/lx/librtld_db/i386/Makefile33
-rw-r--r--usr/src/lib/brand/lx/lx_brand/Makefile49
-rw-r--r--usr/src/lib/brand/lx/lx_brand/Makefile.com100
-rw-r--r--usr/src/lib/brand/lx/lx_brand/amd64/Makefile42
-rw-r--r--usr/src/lib/brand/lx/lx_brand/amd64/lx_crt.s62
-rw-r--r--usr/src/lib/brand/lx/lx_brand/amd64/lx_handler.s53
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/capabilities.c516
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/clock.c192
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/clone.c696
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/debug.c171
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/dir.c82
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/fcntl.c88
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/file.c347
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/fork.c184
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c1704
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_provider.d39
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mapfile47
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mapfile-vers47
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mem.c664
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/misc.c359
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/module.c90
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mount.c540
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c1506
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/ptrace.c105
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/sendfile.c143
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/signal.c2378
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/stack.c338
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/statfs.c348
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/sysctl.c137
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/sysv_ipc.c987
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/time.c132
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/truncate.c173
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/Makefile48
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/lx_crt.s65
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s91
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_debug.h54
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h175
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_mount.h163
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h65
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h289
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_sigstack.h78
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h147
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_statfs.h85
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h202
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_sysv_ipc.h222
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_thread.h80
-rw-r--r--usr/src/lib/brand/lx/lx_init/Makefile71
-rw-r--r--usr/src/lib/brand/lx/lx_init/lxinit.c872
-rw-r--r--usr/src/lib/brand/lx/lx_init/pipe_stream.c326
-rw-r--r--usr/src/lib/brand/lx/lx_init/pipe_stream.h48
-rw-r--r--usr/src/lib/brand/lx/lx_init/run_command.c281
-rw-r--r--usr/src/lib/brand/lx/lx_init/run_command.h32
-rw-r--r--usr/src/lib/brand/lx/lx_lockd/Makefile62
-rw-r--r--usr/src/lib/brand/lx/lx_lockd/lockd.c568
-rw-r--r--usr/src/lib/brand/lx/lx_lockd/nfs_tbind.c1832
-rw-r--r--usr/src/lib/brand/lx/lx_support/Makefile54
-rw-r--r--usr/src/lib/brand/lx/lx_support/lx_support.c392
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/Makefile39
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/Makefile.com85
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/amd64/Makefile42
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/amd64/vdso_subr.s131
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/common/mapfile-vers59
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/common/vdso_defs.h42
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/common/vdso_main.c139
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/i386/Makefile43
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/i386/vdso_subr.s92
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/tools/Makefile42
-rw-r--r--usr/src/lib/brand/lx/lx_vdso/tools/vdso_tool.c388
-rw-r--r--usr/src/lib/brand/lx/netfiles/Makefile47
-rw-r--r--usr/src/lib/brand/lx/testing/Makefile36
-rw-r--r--usr/src/lib/brand/lx/testing/Readme_ltp294
-rw-r--r--usr/src/lib/brand/lx/testing/ltp_skiplist269
-rw-r--r--usr/src/lib/brand/lx/testing/ltp_tests1
-rw-r--r--usr/src/lib/brand/lx/testing/pts_ignorelist366
-rw-r--r--usr/src/lib/brand/lx/zone/Makefile70
-rw-r--r--usr/src/lib/brand/lx/zone/SUNWlx.xml34
-rw-r--r--usr/src/lib/brand/lx/zone/SUNWlx26.xml35
-rw-r--r--usr/src/lib/brand/lx/zone/config.xml105
-rw-r--r--usr/src/lib/brand/lx/zone/lx_boot.ksh92
-rw-r--r--usr/src/lib/brand/lx/zone/lx_boot_zone_busybox.ksh168
-rw-r--r--usr/src/lib/brand/lx/zone/lx_boot_zone_debian.ksh172
-rw-r--r--usr/src/lib/brand/lx/zone/lx_boot_zone_redhat.ksh361
-rw-r--r--usr/src/lib/brand/lx/zone/lx_boot_zone_ubuntu.ksh139
-rw-r--r--usr/src/lib/brand/lx/zone/lx_install.ksh194
-rw-r--r--usr/src/lib/brand/lx/zone/platform.xml163
-rw-r--r--usr/src/lib/brand/shared/zone/common.ksh98
-rw-r--r--usr/src/lib/brand/shared/zone/uninstall.ksh50
-rw-r--r--usr/src/lib/common/i386/crtn.s1
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/libtopo.h5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mapfile-vers2
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h18
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_string.c64
-rwxr-xr-x[-rw-r--r--]usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh10
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml4
-rw-r--r--usr/src/lib/fm/topo/modules/Makefile.plugin5
-rw-r--r--usr/src/lib/fm/topo/modules/common/Makefile2
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c65
-rw-r--r--usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c51
-rw-r--r--usr/src/lib/fm/topo/modules/common/nic/Makefile26
-rw-r--r--usr/src/lib/fm/topo/modules/common/nic/topo_nic.c241
-rw-r--r--usr/src/lib/fm/topo/modules/common/nic/topo_nic.h34
-rw-r--r--usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c72
-rw-r--r--usr/src/lib/fm/topo/modules/common/shared/topo_port.c130
-rw-r--r--usr/src/lib/fm/topo/modules/common/shared/topo_port.h36
-rw-r--r--usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c185
-rw-r--r--usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h37
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile4
-rw-r--r--usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci3
-rw-r--r--usr/src/lib/krb5/plugins/preauth/pkinit/Makefile.com2
-rw-r--r--usr/src/lib/libbc/inc/include/sys/socket.h4
-rw-r--r--usr/src/lib/libbe/common/be_list.c1
-rw-r--r--usr/src/lib/libbrand/common/libbrand.c15
-rw-r--r--usr/src/lib/libbsm/common/adt.c102
-rw-r--r--usr/src/lib/libbunyan/Makefile42
-rw-r--r--usr/src/lib/libbunyan/Makefile.com36
-rw-r--r--usr/src/lib/libbunyan/amd64/Makefile19
-rw-r--r--usr/src/lib/libbunyan/common/bunyan.c913
-rw-r--r--usr/src/lib/libbunyan/common/bunyan.h88
-rw-r--r--usr/src/lib/libbunyan/common/bunyan_provider.d32
-rw-r--r--usr/src/lib/libbunyan/common/llib-lbunyan19
-rw-r--r--usr/src/lib/libbunyan/common/mapfile-vers53
-rw-r--r--usr/src/lib/libbunyan/i386/Makefile18
-rw-r--r--usr/src/lib/libbunyan/sparc/Makefile18
-rw-r--r--usr/src/lib/libbunyan/sparcv9/Makefile19
-rw-r--r--usr/src/lib/libc/amd64/Makefile4
-rw-r--r--usr/src/lib/libc/amd64/gen/siginfolst.c2
-rw-r--r--usr/src/lib/libc/amd64/sys/gettimeofday.s60
-rw-r--r--usr/src/lib/libc/i386/Makefile.com4
-rw-r--r--usr/src/lib/libc/i386/gen/siginfolst.c2
-rw-r--r--usr/src/lib/libc/i386/sys/gettimeofday.c50
-rw-r--r--usr/src/lib/libc/i386/sys/gettimeofday.s60
-rw-r--r--usr/src/lib/libc/inc/thr_inlines.h12
-rw-r--r--usr/src/lib/libc/inc/thr_uberdata.h5
-rw-r--r--usr/src/lib/libc/port/gen/getauxv.c15
-rw-r--r--usr/src/lib/libc/port/gen/sh_locks.c2
-rw-r--r--usr/src/lib/libc/port/gen/siglist.c2
-rw-r--r--usr/src/lib/libc/port/gen/str2sig.c3
-rw-r--r--usr/src/lib/libc/port/llib-lc1
-rw-r--r--usr/src/lib/libc/port/mapfile-vers7
-rw-r--r--usr/src/lib/libc/port/stdio/system.c11
-rw-r--r--usr/src/lib/libc/port/sys/epoll.c15
-rw-r--r--usr/src/lib/libc/port/sys/inotify.c142
-rw-r--r--usr/src/lib/libc/port/sys/time_util.c12
-rw-r--r--usr/src/lib/libc/port/sys/zone.c13
-rw-r--r--usr/src/lib/libc/port/threads/sigaction.c74
-rw-r--r--usr/src/lib/libc/port/threads/thr.c13
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com1
-rw-r--r--usr/src/lib/libc/sparc/gen/siginfolst.c2
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com1
-rw-r--r--usr/src/lib/libc/sparcv9/gen/siginfolst.c2
-rw-r--r--usr/src/lib/libctf/Makefile.com41
-rw-r--r--usr/src/lib/libctf/Makefile.shared.com90
-rw-r--r--usr/src/lib/libctf/Makefile.shared.targ30
-rw-r--r--usr/src/lib/libctf/common/ctf_convert.c210
-rw-r--r--usr/src/lib/libctf/common/ctf_diff.c1362
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c2957
-rw-r--r--usr/src/lib/libctf/common/ctf_elfwrite.c422
-rw-r--r--usr/src/lib/libctf/common/ctf_lib.c325
-rw-r--r--usr/src/lib/libctf/common/ctf_merge.c1570
-rw-r--r--usr/src/lib/libctf/common/ctf_subr.c28
-rw-r--r--usr/src/lib/libctf/common/libctf.h48
-rw-r--r--usr/src/lib/libctf/common/libctf_impl.h59
-rw-r--r--usr/src/lib/libctf/common/mapfile-vers36
-rw-r--r--usr/src/lib/libcurses/screen/setupterm.c7
-rw-r--r--usr/src/lib/libdhcpagent/common/dhcpagent_util.c9
-rw-r--r--usr/src/lib/libdladm/Makefile13
-rw-r--r--usr/src/lib/libdladm/Makefile.com9
-rw-r--r--usr/src/lib/libdladm/common/libdladm.c85
-rw-r--r--usr/src/lib/libdladm/common/libdladm.h24
-rw-r--r--usr/src/lib/libdladm/common/libdladm_impl.h7
-rw-r--r--usr/src/lib/libdladm/common/libdllink.c28
-rw-r--r--usr/src/lib/libdladm/common/libdllink.h6
-rw-r--r--usr/src/lib/libdladm/common/libdlmgmt.c25
-rw-r--r--usr/src/lib/libdladm/common/libdloverlay.c908
-rw-r--r--usr/src/lib/libdladm/common/libdloverlay.h107
-rw-r--r--usr/src/lib/libdladm/common/libdlvlan.c2
-rw-r--r--usr/src/lib/libdladm/common/libdlvnic.c38
-rw-r--r--usr/src/lib/libdladm/common/libdlvnic.h3
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c47
-rw-r--r--usr/src/lib/libdladm/common/llib-ldladm2
-rw-r--r--usr/src/lib/libdladm/common/mapfile-vers19
-rw-r--r--usr/src/lib/libdlpi/common/libdlpi.c71
-rw-r--r--usr/src/lib/libdlpi/common/libdlpi.h2
-rw-r--r--usr/src/lib/libdlpi/common/libdlpi_impl.h3
-rw-r--r--usr/src/lib/libdlpi/common/mapfile-vers5
-rw-r--r--usr/src/lib/libdns_sd/java/com/apple/dnssd/DNSSDRecordRegistrar.java12
-rw-r--r--usr/src/lib/libdtrace/Makefile.com10
-rw-r--r--usr/src/lib/libdtrace/common/dt_cg.c50
-rw-r--r--usr/src/lib/libdtrace/common/dt_decl.c4
-rw-r--r--usr/src/lib/libdtrace/common/dt_dis.c20
-rw-r--r--usr/src/lib/libdtrace/common/dt_impl.h1
-rw-r--r--usr/src/lib/libdtrace/common/dt_link.c18
-rw-r--r--usr/src/lib/libdtrace/common/dt_module.c92
-rw-r--r--usr/src/lib/libdtrace/common/dt_open.c45
-rw-r--r--usr/src/lib/libdtrace/common/dt_options.c73
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.c4
-rw-r--r--usr/src/lib/libdtrace/common/dt_program.c9
-rw-r--r--usr/src/lib/libdtrace/common/dt_work.c32
-rw-r--r--usr/src/lib/libdtrace/common/dtrace.h1
-rw-r--r--usr/src/lib/libdtrace/common/mac.d.in66
-rw-r--r--usr/src/lib/libdtrace/common/mac.sed.in45
-rw-r--r--usr/src/lib/libdtrace/common/vnd.d28
-rw-r--r--usr/src/lib/libdwarf/Makefile40
-rw-r--r--usr/src/lib/libdwarf/Makefile.com92
-rw-r--r--usr/src/lib/libdwarf/THIRDPARTYLICENSE30
-rw-r--r--usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/lib/libdwarf/amd64/Makefile19
-rw-r--r--usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h55
-rw-r--r--usr/src/lib/libdwarf/common/config.h143
-rw-r--r--usr/src/lib/libdwarf/common/dwarf.h1078
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_abbrev.c259
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_abbrev.h55
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_addr_finder.c685
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_alloc.c1258
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_alloc.h177
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_arange.c593
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_arange.h71
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_base_types.h123
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_die_deliv.c855
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_die_deliv.h57
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_elf_access.c976
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_elf_access.h55
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_error.c410
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_error.h43
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_form.c963
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame.c2442
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame.h421
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame2.c1540
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame3.c290
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_funcs.c130
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_funcs.h42
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_global.c607
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_global.h124
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_harmless.c226
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_harmless.h31
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_incl.h66
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_init_finish.c577
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_leb.c149
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line.c1951
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line.h331
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line2.c110
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_loc.c1073
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_loc.h46
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_macro.c467
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_macro.h44
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_names.c2408
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_names.h34
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_opaque.h339
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_original_elf_init.c209
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_print_lines.c737
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_pubtypes.c138
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_query.c789
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_ranges.c171
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_sort_line.c733
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_string.c79
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_stubs.c50
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_types.c129
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_types.h41
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_util.c547
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_util.h311
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_vars.c133
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_vars.h41
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_weaks.c130
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_weaks.h41
-rw-r--r--usr/src/lib/libdwarf/common/libdwarf.h2736
-rw-r--r--usr/src/lib/libdwarf/common/libdwarfdefs.h91
-rw-r--r--usr/src/lib/libdwarf/common/malloc_check.c339
-rw-r--r--usr/src/lib/libdwarf/common/malloc_check.h62
-rw-r--r--usr/src/lib/libdwarf/common/mapfile-vers302
-rw-r--r--usr/src/lib/libdwarf/common/pro_alloc.c188
-rw-r--r--usr/src/lib/libdwarf/common/pro_alloc.h42
-rw-r--r--usr/src/lib/libdwarf/common/pro_arange.c337
-rw-r--r--usr/src/lib/libdwarf/common/pro_arange.h62
-rw-r--r--usr/src/lib/libdwarf/common/pro_die.c442
-rw-r--r--usr/src/lib/libdwarf/common/pro_die.h68
-rw-r--r--usr/src/lib/libdwarf/common/pro_encode_nm.c123
-rw-r--r--usr/src/lib/libdwarf/common/pro_encode_nm.h48
-rw-r--r--usr/src/lib/libdwarf/common/pro_error.c97
-rw-r--r--usr/src/lib/libdwarf/common/pro_error.h52
-rw-r--r--usr/src/lib/libdwarf/common/pro_expr.c597
-rw-r--r--usr/src/lib/libdwarf/common/pro_expr.h45
-rw-r--r--usr/src/lib/libdwarf/common/pro_finish.c57
-rw-r--r--usr/src/lib/libdwarf/common/pro_forms.c1182
-rw-r--r--usr/src/lib/libdwarf/common/pro_frame.c598
-rw-r--r--usr/src/lib/libdwarf/common/pro_frame.h132
-rw-r--r--usr/src/lib/libdwarf/common/pro_funcs.c62
-rw-r--r--usr/src/lib/libdwarf/common/pro_incl.h92
-rw-r--r--usr/src/lib/libdwarf/common/pro_init.c261
-rw-r--r--usr/src/lib/libdwarf/common/pro_line.c300
-rw-r--r--usr/src/lib/libdwarf/common/pro_line.h116
-rw-r--r--usr/src/lib/libdwarf/common/pro_macinfo.c472
-rw-r--r--usr/src/lib/libdwarf/common/pro_macinfo.h40
-rw-r--r--usr/src/lib/libdwarf/common/pro_opaque.h484
-rw-r--r--usr/src/lib/libdwarf/common/pro_pubnames.c63
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc.c269
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc.h47
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_stream.c297
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_stream.h63
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_symbolic.c276
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_symbolic.h55
-rw-r--r--usr/src/lib/libdwarf/common/pro_section.c2221
-rw-r--r--usr/src/lib/libdwarf/common/pro_section.h112
-rw-r--r--usr/src/lib/libdwarf/common/pro_types.c296
-rw-r--r--usr/src/lib/libdwarf/common/pro_types.h44
-rw-r--r--usr/src/lib/libdwarf/common/pro_util.h148
-rw-r--r--usr/src/lib/libdwarf/common/pro_vars.c62
-rw-r--r--usr/src/lib/libdwarf/common/pro_weaks.c61
-rw-r--r--usr/src/lib/libdwarf/i386/Makefile18
-rw-r--r--usr/src/lib/libdwarf/sparc/Makefile18
-rw-r--r--usr/src/lib/libdwarf/sparcv9/Makefile19
-rw-r--r--usr/src/lib/libgrubmgmt/common/libgrub_fs.c2
-rw-r--r--usr/src/lib/libidspace/Makefile45
-rw-r--r--usr/src/lib/libidspace/Makefile.com42
-rw-r--r--usr/src/lib/libidspace/amd64/Makefile19
-rw-r--r--usr/src/lib/libidspace/common/libidspace.c25
-rw-r--r--usr/src/lib/libidspace/common/libidspace.h42
-rw-r--r--usr/src/lib/libidspace/common/llib-lidspace19
-rw-r--r--usr/src/lib/libidspace/common/mapfile-vers47
-rw-r--r--usr/src/lib/libidspace/i386/Makefile18
-rw-r--r--usr/src/lib/libidspace/sparc/Makefile18
-rw-r--r--usr/src/lib/libidspace/sparcv9/Makefile19
-rw-r--r--usr/src/lib/libinetutil/common/mapfile-vers1
-rw-r--r--usr/src/lib/libipadm/common/libipadm.c27
-rw-r--r--usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com4
-rw-r--r--usr/src/lib/libnisdb/db_mindex3.cc4
-rw-r--r--usr/src/lib/libnisdb/db_table.cc4
-rw-r--r--usr/src/lib/libnisdb/nis_db.cc8
-rw-r--r--usr/src/lib/libnsl/common/mapfile-vers1
-rw-r--r--usr/src/lib/libnsl/netselect/netselect.c27
-rw-r--r--usr/src/lib/libnvpair/libnvpair.h2
-rw-r--r--usr/src/lib/libnvpair/mapfile-vers2
-rw-r--r--usr/src/lib/libnvpair/nvpair_json.c284
-rw-r--r--usr/src/lib/libofmt/common/mapfile-vers2
-rw-r--r--usr/src/lib/libofmt/common/ofmt.c94
-rw-r--r--usr/src/lib/libofmt/common/ofmt.h8
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.c11
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h5
-rw-r--r--usr/src/lib/libproc/common/Pcore.c1
-rw-r--r--usr/src/lib/libproc/common/Pidle.c1
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c486
-rw-r--r--usr/src/lib/librename/Makefile44
-rw-r--r--usr/src/lib/librename/Makefile.com34
-rw-r--r--usr/src/lib/librename/amd64/Makefile19
-rw-r--r--usr/src/lib/librename/common/librename.c229
-rw-r--r--usr/src/lib/librename/common/librename.h43
-rw-r--r--usr/src/lib/librename/common/llib-lrename19
-rw-r--r--usr/src/lib/librename/common/mapfile-vers41
-rw-r--r--usr/src/lib/librename/i386/Makefile18
-rw-r--r--usr/src/lib/librename/sparc/Makefile18
-rw-r--r--usr/src/lib/librename/sparcv9/Makefile19
-rw-r--r--usr/src/lib/libresolv2_joy/Makefile76
-rw-r--r--usr/src/lib/libresolv2_joy/Makefile.com162
-rw-r--r--usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE185
-rw-r--r--usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/lib/libresolv2_joy/amd64/Makefile31
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/daemon.c81
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/ftruncate.c64
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/gettimeofday.c62
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/mktemp.c156
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/putenv.c27
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/readv.c39
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/setenv.c151
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/setitimer.c29
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strcasecmp.c124
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strdup.c20
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strerror.c94
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strpbrk.c70
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strsep.c88
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/strtoul.c119
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/utimes.c40
-rw-r--r--usr/src/lib/libresolv2_joy/common/bsd/writev.c89
-rw-r--r--usr/src/lib/libresolv2_joy/common/dst/dst_api.c1048
-rw-r--r--usr/src/lib/libresolv2_joy/common/dst/dst_internal.h155
-rw-r--r--usr/src/lib/libresolv2_joy/common/dst/hmac_link.c491
-rw-r--r--usr/src/lib/libresolv2_joy/common/dst/support.c342
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_cidr_ntop.c263
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_cidr_pton.c277
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_data.c46
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_lnaof.c65
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_makeaddr.c68
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_net_ntop.c279
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_net_pton.c407
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_neta.c89
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_netof.c64
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/inet_network.c106
-rw-r--r--usr/src/lib/libresolv2_joy/common/inet/nsap_addr.c111
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns.c154
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns_ho.c1143
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns_nw.c591
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns_p.h52
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns_pr.c268
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/dns_sv.c300
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gai_strerror.c105
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen.c459
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_ho.c391
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_ng.c174
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_nw.c264
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_p.h113
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_pr.c228
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gen_sv.c229
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getaddrinfo.c1253
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gethostent.c1096
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/gethostent_r.c278
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getnameinfo.c334
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getnetent.c345
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getnetent_r.c234
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getnetgrent.c160
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getnetgrent_r.c219
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getprotoent.c176
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getprotoent_r.c223
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getservent.c179
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/getservent_r.c242
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/hesiod.c505
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/hesiod_p.h48
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp.c583
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_ho.c405
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_ng.c253
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_nw.c348
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_p.h60
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_pr.c327
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irp_sv.c346
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irpmarshall.c2301
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irs_data.c254
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irs_data.h63
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/irs_p.h51
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl.c142
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_ho.c578
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_ng.c446
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_nw.c373
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_p.h51
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_pr.c294
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/lcl_sv.c432
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/nis.c156
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/nis_p.h47
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/nul_ng.c127
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/pathnames.h52
-rw-r--r--usr/src/lib/libresolv2_joy/common/irs/util.c109
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/assertions.c94
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/base64.c333
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/bitncmp.c68
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ctl_clnt.c620
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ctl_p.c188
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ctl_p.h28
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ctl_srvr.c787
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ev_connects.c369
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ev_files.c277
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ev_streams.c308
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ev_timers.c499
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/ev_waits.c247
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/eventlib.c933
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/eventlib_p.h281
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/heap.c236
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/hex.c119
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/logging.c716
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/logging_p.h61
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/memcluster.c588
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/movefile.c43
-rw-r--r--usr/src/lib/libresolv2_joy/common/isc/tree.c534
-rw-r--r--usr/src/lib/libresolv2_joy/common/llib-lresolv_joy59
-rw-r--r--usr/src/lib/libresolv2_joy/common/mapfile-vers60
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_date.c129
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_name.c1153
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_netint.c61
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_newmsg.c273
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_parse.c275
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_print.c1242
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_rdata.c300
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_samedomain.c207
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_sign.c387
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_ttl.c162
-rw-r--r--usr/src/lib/libresolv2_joy/common/nameser/ns_verify.c484
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/herror.c129
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/mtctxres.c135
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_comp.c287
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_data.c322
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_debug.c1252
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_debug.h35
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_findzonecut.c722
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_init.c958
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_mkquery.c386
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.c1163
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.h25
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_private.h22
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_query.c440
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_send.c1120
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_sendsigned.c170
-rw-r--r--usr/src/lib/libresolv2_joy/common/resolv/res_update.c213
-rw-r--r--usr/src/lib/libresolv2_joy/common/sunw/sunw_mtctxres.c126
-rw-r--r--usr/src/lib/libresolv2_joy/common/sunw/sunw_updrec.c249
-rw-r--r--usr/src/lib/libresolv2_joy/common/sunw/sunw_wrappers.c23
-rw-r--r--usr/src/lib/libresolv2_joy/i386/Makefile30
-rw-r--r--usr/src/lib/libresolv2_joy/include/Makefile60
-rw-r--r--usr/src/lib/libresolv2_joy/include/arpa/port_inet.h41
-rw-r--r--usr/src/lib/libresolv2_joy/include/arpa/port_nameser.h40
-rw-r--r--usr/src/lib/libresolv2_joy/include/conf/sunoptions.h30
-rw-r--r--usr/src/lib/libresolv2_joy/include/config.h75
-rw-r--r--usr/src/lib/libresolv2_joy/include/err.h62
-rw-r--r--usr/src/lib/libresolv2_joy/include/fd_setsize.h10
-rw-r--r--usr/src/lib/libresolv2_joy/include/hesiod.h39
-rw-r--r--usr/src/lib/libresolv2_joy/include/irp.h107
-rw-r--r--usr/src/lib/libresolv2_joy/include/irs.h348
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/assertions.h123
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/ctl.h112
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/dst.h168
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/eventlib.h206
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/heap.h49
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/irpmarshall.h112
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/list.h118
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/logging.h113
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/memcluster.h50
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/misc.h44
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/platform.h42
-rw-r--r--usr/src/lib/libresolv2_joy/include/isc/tree.h59
-rwxr-xr-xusr/src/lib/libresolv2_joy/include/make_os_version34
-rw-r--r--usr/src/lib/libresolv2_joy/include/make_os_version.sh34
-rw-r--r--usr/src/lib/libresolv2_joy/include/port_after.h539
-rw-r--r--usr/src/lib/libresolv2_joy/include/port_before.h201
-rw-r--r--usr/src/lib/libresolv2_joy/include/port_netdb.h188
-rw-r--r--usr/src/lib/libresolv2_joy/include/port_resolv.h42
-rwxr-xr-xusr/src/lib/libresolv2_joy/include/probe_ipv673
-rw-r--r--usr/src/lib/libresolv2_joy/include/probe_ipv6.sh73
-rw-r--r--usr/src/lib/libresolv2_joy/include/res_update.h88
-rw-r--r--usr/src/lib/libresolv2_joy/include/resolv_mt.h47
-rw-r--r--usr/src/lib/libresolv2_joy/include/sunw_port_after.h123
-rw-r--r--usr/src/lib/libresolv2_joy/include/sunw_port_before.h43
-rw-r--r--usr/src/lib/libresolv2_joy/include/sys/bitypes.h37
-rw-r--r--usr/src/lib/libresolv2_joy/include/sys/cdefs.h144
-rw-r--r--usr/src/lib/libresolv2_joy/sparc/Makefile30
-rw-r--r--usr/src/lib/libresolv2_joy/sparcv9/Makefile38
-rw-r--r--usr/src/lib/libscf/inc/libscf.h6
-rw-r--r--usr/src/lib/libsff/Makefile44
-rw-r--r--usr/src/lib/libsff/Makefile.com34
-rw-r--r--usr/src/lib/libsff/amd64/Makefile19
-rw-r--r--usr/src/lib/libsff/common/libsff.c1412
-rw-r--r--usr/src/lib/libsff/common/libsff.h101
-rw-r--r--usr/src/lib/libsff/common/llib-lsff19
-rw-r--r--usr/src/lib/libsff/common/mapfile-vers37
-rw-r--r--usr/src/lib/libsff/common/sff.h221
-rw-r--r--usr/src/lib/libsff/i386/Makefile18
-rw-r--r--usr/src/lib/libsff/sparc/Makefile18
-rw-r--r--usr/src/lib/libshare/nfs/libshare_nfs.c14
-rw-r--r--usr/src/lib/libshell/Makefile1
-rw-r--r--usr/src/lib/libshell/Makefile.doc77
-rw-r--r--usr/src/lib/libshell/common/COMPATIBILITY134
-rw-r--r--usr/src/lib/libshell/common/DESIGN170
-rw-r--r--usr/src/lib/libshell/common/OBSOLETE152
-rw-r--r--usr/src/lib/libshell/common/README232
-rw-r--r--usr/src/lib/libshell/common/RELEASE2204
-rw-r--r--usr/src/lib/libshell/common/TYPES182
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/1.pngbin236 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/10.pngbin284 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/2.pngbin261 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/3.pngbin265 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/4.pngbin260 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/5.pngbin261 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/6.pngbin278 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/7.pngbin253 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/8.pngbin275 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/callouts/9.pngbin284 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_bourne.pngbin130 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_i18n.pngbin124 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_ksh.pngbin122 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_ksh88.pngbin124 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_ksh93.pngbin140 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_l10n.pngbin118 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/images/tag_perf.pngbin127 -> 0 bytes
-rw-r--r--usr/src/lib/libshell/misc/shell_styleguide.docbook1464
-rw-r--r--usr/src/lib/libsmartsshd/Makefile48
-rw-r--r--usr/src/lib/libsmartsshd/Makefile.com46
-rw-r--r--usr/src/lib/libsmartsshd/amd64/Makefile32
-rw-r--r--usr/src/lib/libsmartsshd/common/llib-lsmartsshd32
-rw-r--r--usr/src/lib/libsmartsshd/common/mapfile-vers48
-rw-r--r--usr/src/lib/libsmartsshd/common/sshd-plugin.c193
-rw-r--r--usr/src/lib/libsmartsshd/i386/Makefile31
-rw-r--r--usr/src/lib/libumem/amd64/umem_genasm.c2
-rw-r--r--usr/src/lib/libvnd/Makefile50
-rw-r--r--usr/src/lib/libvnd/Makefile.com39
-rw-r--r--usr/src/lib/libvnd/amd64/Makefile19
-rw-r--r--usr/src/lib/libvnd/common/libvnd.c550
-rw-r--r--usr/src/lib/libvnd/common/libvnd.h84
-rw-r--r--usr/src/lib/libvnd/common/llib-lvnd19
-rw-r--r--usr/src/lib/libvnd/common/mapfile-vers55
-rw-r--r--usr/src/lib/libvnd/i386/Makefile18
-rw-r--r--usr/src/lib/libwanboot/Makefile.com2
-rw-r--r--usr/src/lib/libzdoor/Makefile48
-rw-r--r--usr/src/lib/libzdoor/Makefile.com50
-rw-r--r--usr/src/lib/libzdoor/amd64/Makefile32
-rw-r--r--usr/src/lib/libzdoor/common/llib-lzdoor34
-rw-r--r--usr/src/lib/libzdoor/common/mapfile-vers48
-rw-r--r--usr/src/lib/libzdoor/common/zdoor-int.c324
-rw-r--r--usr/src/lib/libzdoor/common/zdoor-int.h64
-rw-r--r--usr/src/lib/libzdoor/common/zdoor.c437
-rw-r--r--usr/src/lib/libzdoor/common/zerror.c117
-rw-r--r--usr/src/lib/libzdoor/common/zerror.h48
-rw-r--r--usr/src/lib/libzdoor/common/ztree.c344
-rw-r--r--usr/src/lib/libzdoor/common/ztree.h88
-rw-r--r--usr/src/lib/libzdoor/i386/Makefile31
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h2
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c20
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h3
-rw-r--r--usr/src/lib/libzfs/common/libzfs_iter.c15
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c9
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c1
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c40
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers3
-rw-r--r--usr/src/lib/libzonecfg/Makefile.com17
-rw-r--r--usr/src/lib/libzonecfg/common/getzoneent.c145
-rw-r--r--usr/src/lib/libzonecfg/common/libzonecfg.c853
-rw-r--r--usr/src/lib/libzonecfg/common/mapfile-vers14
-rw-r--r--usr/src/lib/libzonecfg/dtd/zonecfg.dtd.115
-rw-r--r--usr/src/lib/libzpool/common/sys/zfs_context.h2
-rw-r--r--usr/src/lib/mergeq/mergeq.c606
-rw-r--r--usr/src/lib/mergeq/mergeq.h52
-rw-r--r--usr/src/lib/mergeq/workq.c311
-rw-r--r--usr/src/lib/mergeq/workq.h52
-rw-r--r--usr/src/lib/nsswitch/dns/Makefile.com2
-rw-r--r--usr/src/lib/nsswitch/dns/common/dns_common.h4
-rw-r--r--usr/src/lib/nsswitch/dns/common/dns_mt.c155
-rw-r--r--usr/src/lib/nsswitch/dns/common/gethostent.c8
-rw-r--r--usr/src/lib/nsswitch/dns/common/gethostent6.c4
-rw-r--r--usr/src/lib/pkcs11/pkcs11_tpm/Makefile.com2
-rw-r--r--usr/src/lib/pysolaris/Makefile.com1
-rw-r--r--usr/src/lib/scsi/libscsi/common/libscsi.h6
-rw-r--r--usr/src/lib/scsi/libscsi/common/scsi_engine.c61
-rw-r--r--usr/src/lib/scsi/libscsi/libscsi_api.map2
-rw-r--r--usr/src/lib/scsi/libscsi/mapfile-vers4
-rw-r--r--usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c44
-rw-r--r--usr/src/lib/varpd/Makefile33
-rw-r--r--usr/src/lib/varpd/Makefile.plugin19
-rw-r--r--usr/src/lib/varpd/direct/Makefile40
-rw-r--r--usr/src/lib/varpd/direct/Makefile.com38
-rw-r--r--usr/src/lib/varpd/direct/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/direct/common/libvarpd_direct.c411
-rw-r--r--usr/src/lib/varpd/direct/common/llib-lvarpd_direct18
-rw-r--r--usr/src/lib/varpd/direct/common/mapfile-vers35
-rw-r--r--usr/src/lib/varpd/direct/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/direct/sparc/Makefile18
-rw-r--r--usr/src/lib/varpd/direct/sparcv9/Makefile19
-rw-r--r--usr/src/lib/varpd/files/Makefile40
-rw-r--r--usr/src/lib/varpd/files/Makefile.com42
-rw-r--r--usr/src/lib/varpd/files/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files.c605
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files_json.c936
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files_json.h52
-rw-r--r--usr/src/lib/varpd/files/common/llib-lvarpd_files18
-rw-r--r--usr/src/lib/varpd/files/common/mapfile-vers35
-rw-r--r--usr/src/lib/varpd/files/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/files/sparc/Makefile18
-rw-r--r--usr/src/lib/varpd/files/sparcv9/Makefile19
-rw-r--r--usr/src/lib/varpd/libvarpd/Makefile55
-rw-r--r--usr/src/lib/varpd/libvarpd/Makefile.com53
-rw-r--r--usr/src/lib/varpd/libvarpd/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd.c360
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd.h77
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c650
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_client.c626
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_client.h92
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_door.c469
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h247
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c584
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c53
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c586
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c269
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c299
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h419
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_util.c97
-rw-r--r--usr/src/lib/varpd/libvarpd/common/llib-lvarpd19
-rw-r--r--usr/src/lib/varpd/libvarpd/common/mapfile-plugin57
-rw-r--r--usr/src/lib/varpd/libvarpd/common/mapfile-vers113
-rw-r--r--usr/src/lib/varpd/libvarpd/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/libvarpd/sparc/Makefile18
-rw-r--r--usr/src/lib/varpd/libvarpd/sparcv9/Makefile19
-rw-r--r--usr/src/lib/varpd/svp/Makefile40
-rw-r--r--usr/src/lib/varpd/svp/Makefile.com54
-rw-r--r--usr/src/lib/varpd/svp/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp.c1138
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp.h357
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_conn.c1031
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_crc.c53
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_host.c171
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_loop.c210
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h236
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c821
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c474
-rw-r--r--usr/src/lib/varpd/svp/common/libvarpd_svp_timer.c150
-rw-r--r--usr/src/lib/varpd/svp/common/llib-lvarpd_svp18
-rw-r--r--usr/src/lib/varpd/svp/common/mapfile-vers35
-rw-r--r--usr/src/lib/varpd/svp/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/svp/sparc/Makefile18
-rw-r--r--usr/src/lib/varpd/svp/sparcv9/Makefile19
-rw-r--r--usr/src/lib/xml/os_dtd.c238
-rw-r--r--usr/src/lib/xml/os_dtd.h49
708 files changed, 142580 insertions, 5739 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 36367793ac..0f6aa5a0bf 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -22,7 +22,7 @@
#
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012 by Delphix. All rights reserved.
-# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+# Copyright 2015, Joyent, Inc.
# Copyright (c) 2013 Gary Mills
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
# Copyright (c) 2015 Gary Mills
@@ -92,6 +92,7 @@ SUBDIRS += \
libbrand \
libbsdmalloc \
libbsm \
+ libbunyan \
libc_db \
libcfgadm \
libcmd \
@@ -118,6 +119,7 @@ SUBDIRS += \
libdscfg \
libdtrace \
libdtrace_jni \
+ libdwarf \
libefi \
libelfsign \
libeti \
@@ -135,6 +137,7 @@ SUBDIRS += \
libgss \
libhotplug \
libidmap \
+ libidspace \
libilb \
libima \
libinetsvc \
@@ -183,9 +186,11 @@ SUBDIRS += \
libraidcfg \
librcm \
librdc \
+ librename \
libreparse \
libresolv \
libresolv2 \
+ libresolv2_joy \
librestart \
librpcsvc \
librsm \
@@ -198,11 +203,13 @@ SUBDIRS += \
libsec \
libsecdb \
libsendfile \
+ libsff \
libshare \
libshell \
libsip \
libsldap \
libslp \
+ libsmartsshd \
libsmbfs \
libsmbios \
libsmedia \
@@ -226,6 +233,7 @@ SUBDIRS += \
libunistat \
libuuid \
libuutil \
+ libvnd \
libvolmgt \
libvrrpadm \
libvscan \
@@ -236,6 +244,7 @@ SUBDIRS += \
libxcurses \
libxcurses2 \
libxnet \
+ libzdoor \
libzfs \
libzfs_core \
libzfs_jni \
@@ -254,9 +263,6 @@ SUBDIRS += \
pkcs11 \
policykit \
print \
- pylibbe \
- pysolaris \
- pyzfs \
raidcfg_plugins \
rpcsec_gss \
sasl_plugins \
@@ -266,6 +272,7 @@ SUBDIRS += \
sun_fc \
sun_sas \
udapl \
+ varpd \
watchmalloc \
$($(MACH)_SUBDIRS)
@@ -338,6 +345,7 @@ MSGSUBDIRS= \
libshell \
libsldap \
libslp \
+ libsmartsshd \
libsmbfs \
libsmedia \
libsum \
@@ -349,10 +357,10 @@ MSGSUBDIRS= \
libwanbootutil \
libzfs \
libzonecfg \
+ libzdoor \
madv \
mpss \
pam_modules \
- pyzfs \
rpcsec_gss \
$($(MACH)_MSGSUBDIRS)
@@ -372,6 +380,7 @@ HDRSUBDIRS= \
libast \
libbrand \
libbsm \
+ libbunyan \
libc \
libcmd \
libcmdutils \
@@ -388,6 +397,7 @@ HDRSUBDIRS= \
libdhcputil \
libdisasm \
libdiskmgt \
+ libdwarf \
libdladm \
libdll \
libdlpi \
@@ -404,6 +414,7 @@ HDRSUBDIRS= \
libgen \
libgrubmgmt \
libidmap \
+ libidspace \
libilb \
libima \
libinetsvc \
@@ -440,6 +451,7 @@ HDRSUBDIRS= \
libraidcfg \
librcm \
librdc \
+ librename \
libreparse \
librestart \
librpcsvc \
@@ -448,6 +460,7 @@ HDRSUBDIRS= \
libsasl \
libscf \
libsec \
+ libsff \
libshare \
libshell \
libsip \
@@ -473,6 +486,7 @@ HDRSUBDIRS= \
libumem \
libunistat \
libuutil \
+ libvnd \
libvolmgt \
libvrrpadm \
libvscan \
@@ -571,10 +585,10 @@ dbusdeps: libsecdb libtsol libinetutil libscf libuutil libgen libsmbios
# libc libm libmd libmp libnsl libnvpair libsocket
abi: libctf libmapmalloc libproc
auditd_plugins: libbsm libsecdb libgss libmtmalloc
-brand: libzonecfg libmapmalloc
+brand: libzonecfg libmapmalloc libipadm libcmdutils libproc librpcsvc
cfgadm_plugins: libdevice libdevinfo libhotplug librcm hbaapi libkstat libscf
fm: libexacct libipmi libzfs scsi libdevinfo libdevid libcfgadm \
- libcontract libsysevent ../cmd/sgs/libelf
+ libcontract libsysevent ../cmd/sgs/libelf libdladm
$(SPARC_BLD)fm: libpri
gss_mechs/mech_dh: libgss
gss_mechs/mech_dummy: libgss
@@ -586,11 +600,13 @@ libadt_jni: libbsm
libadutils: libldap5 libresolv2
libbe: libzfs libinstzones libuuid libgen libdevinfo libefi libficl
libbsm: libinetutil libscf libsecdb libtsol
+libbunyan: libnvpair
libcfgadm: libdevinfo
libcmd: libsum libast
libcmdutils: libavl
libcpc: libpctx
libcrypt: libgen
+libctf: libdwarf
libdevid: libdevinfo
libdevinfo: libsec libgen
libdhcpagent: libdhcputil libuuid libdlpi libcontract
@@ -598,7 +614,7 @@ libdhcputil: libgen libinetutil libdlpi
libdiskmgt: libdevid libdevinfo libadm libefi libkstat libsysevent
$(INTEL_BLD)libdiskmgt: libfdisk
libdladm: libdevinfo libinetutil libscf librcm libexacct libkstat \
- libpool
+ libpool varpd
libdll: libast
libdlpi: libinetutil libdladm
libds: libsysevent
@@ -617,6 +633,7 @@ libfsmgt: libkstat
libgrubmgmt: libdevinfo libzfs libfstyp libefi
$(INTEL_BLD)libgrubmgmt: libfdisk
libidmap: libavl libuutil
+libidspace: libumem
libinetsvc: libscf
libinstzones: libzonecfg libcontract
libipadm: libinetutil libdlpi libdhcpagent libdladm libsecdb
@@ -647,10 +664,12 @@ libsasl: libgss pkcs11
libsaveargs: libdisasm
libscf: libuutil libgen libsmbios
libsec: libavl libidmap
+libsff: libnvpair
libshare: libscf libzfs libuuid libfsmgt libsecdb libumem libsmbfs
libshell: libast libcmd libdll libsecdb
libsip: libmd5
libsldap: libldap5 libscf
+libsmartsshd: libc libcontract
libsmbfs: libkrb5 libsec libidmap pkcs11
libsmbios: libdevinfo
libsrpt: libstmf
@@ -671,6 +690,7 @@ libvolmgt: libadm
libvrrpadm: libdladm libscf
libvscan: libscf libsecdb
libwanboot: libresolv2 libdevinfo libinetutil libdhcputil
+libzdoor: libc libzonecfg libcontract
libzfs: libdevid libgen libuutil libadm libavl libefi libidmap \
libumem libtsol libzfs_core
libzfs_jni: libdiskmgt libzfs
@@ -681,7 +701,8 @@ libzpool: libavl libumem libcmdutils libsysevent
madv: libgen
mpapi: libpthread libdevinfo libsysevent
mpss: libgen
-nsswitch: libadutils libidmap libdns_sd libscf libldap5 libsldap
+nsswitch: libadutils libidmap libdns_sd libscf libldap5 libsldap \
+ libresolv2_joy
pam_modules: libproject passwdutil smbsrv libtsnet libpam libbsm libsecdb
passwdutil: libsldap
pkcs11: libcryptoutil libgen libuuid
@@ -701,6 +722,8 @@ storage: libdevice libdevinfo libdevid
sun_fc: libdevinfo libsysevent
sun_sas: libdevinfo libsysevent libkstat libdevid
udapl: libdevinfo libdladm
+varpd: libavl libidspace libumem libnsl libnvpair libmd5 librename \
+ libbunyan libcmdutils
#
# The reason this rule checks for the existence of the
diff --git a/usr/src/lib/Makefile.astmsg b/usr/src/lib/Makefile.astmsg
index 096805e825..ff8202d03a 100644
--- a/usr/src/lib/Makefile.astmsg
+++ b/usr/src/lib/Makefile.astmsg
@@ -47,8 +47,8 @@ MSGLIBNAME= $(LIBRARY:.a=)
ASTMSGCATALOG= $(ROOT)/usr/lib/locale/C/LC_MESSAGES/$(MSGLIBNAME)
$(DO_BUILD_AST_CATALOGS)ASTMSGCC= \
- PATH="/usr/ast/bin/:/bin:/usr/bin" \
- /usr/bin/ksh93 /usr/ast/bin/msgcc >>msgcc.out 2>&1
+ PATH="$(ASTBINDIR):/bin:/usr/bin" \
+ /usr/bin/ksh93 $(MSGCC) >>msgcc.out 2>&1
ASTMSGS= $(OBJECTS:%.o=msgs/%.mso)
diff --git a/usr/src/lib/Makefile.lib b/usr/src/lib/Makefile.lib
index d891e418a7..79db7f9bec 100644
--- a/usr/src/lib/Makefile.lib
+++ b/usr/src/lib/Makefile.lib
@@ -21,6 +21,7 @@
# Copyright 2015 Gary Mills
# Copyright 2015 Igor Kozhukhov <ikozhukhov@gmail.com>
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, Joyent, Inc.
#
#
# Definitions common to libraries.
@@ -135,6 +136,23 @@ SONAME= $(DYNLIB)
# combining relocations into one relocation table reduces startup costs.
# All options are tunable to allow overload/omission from lower makefiles.
+#
+# DTrace related rules
+#
+# These allow for multiple USDT providers to be specified by a library.
+# If a library needs to break up the set of objects that are passed to
+# the dtrace -G invocation, then they can place the following in heir
+# Makefile.com:
+#
+# pics/<provider>.o := USDT_G_PICS = <files>
+#
+# <provider> should be replaced with the basename of one of the USDT
+# providers specified in USDT_PROVIDERS in their Makefile.com.
+#
+USDT_HEADERS= $(USDT_PROVIDERS:%.d=%_impl.h)
+USDT_PICS= $(USDT_PROVIDERS:%.d=pics/%.o)
+USDT_G_PICS= $(PICS)
+
HSONAME= -h$(SONAME)
DYNFLAGS= $(HSONAME) $(ZTEXT) $(ZDEFS) $(BDIRECT) \
@@ -157,7 +175,7 @@ SRCS= $(OBJECTS:%.o=$(SRCDIR)/%.c)
# overridden locally when extra processing is needed
BUILD.AR= $(AR) $(ARFLAGS) $@ $(AROBJS)
BUILD.SO= $(CC) $(CFLAGS) -o $@ $(GSHARED) $(DYNFLAGS) \
- $(PICS) $(EXTPICS) $(LDLIBS)
+ $(PICS) $(EXTPICS) $(USDT_PICS) $(LDLIBS)
BUILDCCC.SO= $(CCC) $(CCFLAGS) -o $@ $(GSHARED) $(DYNFLAGS) \
$(PICS) $(EXTPICS) $(LDLIBS)
@@ -254,3 +272,15 @@ TARGETMACH= $(MACH)
# shouldn't override this - they should override $(CLOBBERFILES) instead.
#
CLOBBERTARGFILES= $(LIBS) $(DYNLIB) $(CLOBBERFILES)
+
+#
+# Define the default ctfdiff invocation used to check a list of types
+# supplied by a user of a library. The goal is to validate that a given
+# series of types is the same in both a 32-bit and 64-bit artifact. This
+# is only defined if we have a 64-bit build to do.
+#
+TYPECHECK_LIB32 = $(TYPECHECK_LIB:%=$(MACH)/%)
+TYPECHECK_LIB64 = $(TYPECHECK_LIB:%=$(MACH64)/%)
+TYPECHECK_LIST= $(TYPELIST:%=-T %)
+$(BUILD64)TYPECHECK.lib = $(CTFDIFF) -t -I $(TYPECHECK_LIST) $(TYPECHECK_LIB32) $(TYPECHECK_LIB64)
+TYPECHECK = $(TYPECHECK_LIB:%=%.typecheck)
diff --git a/usr/src/lib/Makefile.targ b/usr/src/lib/Makefile.targ
index 4769c64d54..2798192343 100644
--- a/usr/src/lib/Makefile.targ
+++ b/usr/src/lib/Makefile.targ
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, Joyent, Inc.
#
#
@@ -90,7 +91,7 @@ $(LIBRARY): objs .WAIT $$(OBJS)
$(DYNLIB): $$(MAPFILES)
-$(DYNLIB): pics .WAIT $$(PICS) $$(ALTPICS) $$(EXTPICS)
+$(DYNLIB): pics $(USDT_HEADERS) .WAIT $$(PICS) $$(ALTPICS) $$(EXTPICS) .WAIT $(USDT_PICS)
$(BUILD.SO)
$(POST_PROCESS_SO)
@@ -104,9 +105,12 @@ $(LINTLIB): $$(SRCS)
lintcheck: $$(SRCS)
$(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS)
+$(TYPECHECK): $(TYPECHECK_LIB32) $(TYPECHECK_LIB64)
+ $(TYPECHECK.lib)
+
clobber: clean
-$(RM) $(CLOBBERTARGFILES)
clean:
- -$(RM) $(OBJS)
+ -$(RM) $(OBJS) $(USDT_HEADERS) $(USDT_PICS)
-$(RM) $(PICS) $(DUPLICATE_SRC) $(LINTOUT) $(LINTLIB) $(CLEANFILES)
diff --git a/usr/src/lib/Makefile.usdt b/usr/src/lib/Makefile.usdt
new file mode 100644
index 0000000000..17140161ad
--- /dev/null
+++ b/usr/src/lib/Makefile.usdt
@@ -0,0 +1,28 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# This makefile contains the necessary targets for USDT providers; it should
+# be included after Makefile.targ. (It is in a separate file rather than in
+# Makefile.targ because the dependency on $(USDT_G_PICS) is incompatible with
+# libraries that dynamically define $(OBJECTS).)
+#
+pics/%.o: $(SRCDIR)/%.d $(USDT_G_PICS)
+ $(COMPILE.d) -o $@ -s $< $(USDT_G_PICS)
+ $(POST_PROCESS_O)
+
+%_impl.h: $(SRCDIR)/%.d
+ $(DTRACE) -h -o $@ -s $<
+
diff --git a/usr/src/lib/brand/Makefile b/usr/src/lib/brand/Makefile
index 05bfc54764..cd19a0bf2c 100644
--- a/usr/src/lib/brand/Makefile
+++ b/usr/src/lib/brand/Makefile
@@ -30,6 +30,9 @@ include ../../Makefile.master
# Build everything in parallel; use .WAIT for dependencies
.PARALLEL:
+i386_SUBDIRS= lx
+i386_MSGSUBDIRS= lx
+
SUBDIRS= shared .WAIT sn1 solaris10 ipkg labeled $($(MACH)_SUBDIRS)
MSGSUBDIRS= solaris10 shared $($(MACH)_MSGSUBDIRS)
diff --git a/usr/src/lib/brand/lx/Makefile b/usr/src/lib/brand/lx/Makefile
new file mode 100644
index 0000000000..bdf0c9f441
--- /dev/null
+++ b/usr/src/lib/brand/lx/Makefile
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2017 Joyent, Inc.
+#
+
+default: all
+
+include Makefile.lx
+
+# Build everything in parallel; use .WAIT for dependencies
+.PARALLEL:
+
+SUBDIRS= librtld_db lx_support lx_init lx_lockd lx_brand netfiles \
+ zone lx_vdso testing .WAIT
+MSGSUBDIRS= lx_brand lx_support zone
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+_msg: $(MSGSUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/brand/lx/Makefile.lx b/usr/src/lib/brand/lx/Makefile.lx
new file mode 100644
index 0000000000..4db4679cef
--- /dev/null
+++ b/usr/src/lib/brand/lx/Makefile.lx
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/brand/lx/Makefile.lx
+#
+# include global definitions
+
+BRAND= lx
+
+include $(SRC)/lib/brand/Makefile.brand
+
diff --git a/usr/src/lib/brand/lx/librtld_db/Makefile b/usr/src/lib/brand/lx/librtld_db/Makefile
new file mode 100644
index 0000000000..2fc0a818f6
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/Makefile
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+default: all
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+LINT_SUBDIRS= $(MACH)
+$(BUILD64)LINT_SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber: $(SUBDIRS)
+
+lint: $(LINT_SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/brand/lx/librtld_db/Makefile.com b/usr/src/lib/brand/lx/librtld_db/Makefile.com
new file mode 100644
index 0000000000..202cc0fe7b
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/Makefile.com
@@ -0,0 +1,83 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = lx_librtld_db.a
+VERS = .1
+COBJS = lx_librtld_db.o
+OBJECTS = $(COBJS) $(COBJS64)
+
+include $(SRC)/lib/Makefile.lib
+include ../../Makefile.lx
+
+CSRCS = $(COBJS:%o=../common/%c)
+SRCS = $(CSRCS)
+
+SRCDIR = ../common
+UTSBASE = $(SRC)/uts
+
+#
+# ATTENTION:
+# Librtl_db brand plugin libraries should NOT directly invoke any
+# libproc.so interfaces or be linked against libproc. If a librtl_db
+# brand plugin library uses libproc.so interfaces then it may break
+# any other librtld_db consumers (like mdb) that tries to attach
+# to a branded process. The only safe interfaces that the a librtld_db
+# brand plugin library can use to access a target process are the
+# proc_service(3PROC) apis.
+#
+DYNFLAGS += $(VERSREF) -M../common/mapfile-vers
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lrtld_db
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I../ -I$(UTSBASE)/common/brand/lx \
+ -I$(SRC)/cmd/sgs/librtld_db/common \
+ -I$(SRC)/cmd/sgs/include \
+ -I$(SRC)/cmd/sgs/include/$(MACH)
+
+ROOTLIBDIR = $(ROOT)/usr/lib/brand/lx
+ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/lx/$(MACH64)
+
+#
+# The top level Makefiles define define TEXT_DOMAIN. But librtld_db.so.1
+# isn't internationalized and this library won't be either. The only
+# messages that this library can generate are messages used for debugging
+# the operation of the library itself.
+#
+DTEXTDOM =
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+pics/%64.o: ../common/%.c
+ $(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/brand/lx/librtld_db/amd64/Makefile b/usr/src/lib/brand/lx/librtld_db/amd64/Makefile
new file mode 100644
index 0000000000..726e7ef6d3
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/amd64/Makefile
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+COBJS64 = lx_librtld_db64.o
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+DYNFLAGS += -Mmapfile-vers
+
+CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB)
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers b/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers
new file mode 100644
index 0000000000..4893b02998
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/amd64/mapfile-vers
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+ global:
+ rtld_db_brand_ops64;
+};
diff --git a/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c b/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c
new file mode 100644
index 0000000000..ddea4f910d
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/common/lx_librtld_db.c
@@ -0,0 +1,852 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/link.h>
+#include <libproc.h>
+#include <proc_service.h>
+#include <rtld_db.h>
+#include <synch.h>
+
+#include <sys/lx_brand.h>
+
+/*
+ * Overview of this library derived from the original "BrandZ" PSARC design
+ * document.
+ *
+ * Since Linux binaries are standard ELF objects, Illumos debug tools (i.e. mdb
+ * or ptools) are able to process them in essentially the same way that Illumos
+ * binaries are processed. The main objective is to retrieve symbols and
+ * thereby aid debugging and observability. Unfortunately, most Linux
+ * distributions strip(1) their binaries as a misguided "optimization" so the
+ * majority of the useful debugging information is lost.
+ *
+ * The debug tools use interfaces provided by librtld_db to debug live
+ * processes and core files. librtld_db discovers ELF objects which have been
+ * mapped into the target's address space and reports these back to the tool.
+ * The librtld_db library understands enough of the internals of the Illumos
+ * runtime linker to iterate over the linker's private link maps and process
+ * the objects it finds. librtld_db allows our tools to debug the Illumos
+ * portions of a branded process (e.g. the brand library, libc, etc.) but they
+ * can't understand any Linux objects that are mapped into the address space
+ * because the Illumos linker only has Illumos objects on its link maps.
+ *
+ * In order to give the tools visibility into Linux binaries, a brand helper
+ * framework is implemented in librtld_db. When librtld_db is asked to examine
+ * a branded target process or core file, it uses the AT_SUN_BRANDNAME aux
+ * vector to get our brand name (lx). It then dlopen-s this lx_librtld_db.so
+ * helper library.
+ *
+ * Once loaded, this helper library is responsible for finding any lx-specific
+ * information it needs, such as the Linux equivalent LDDATA aux entry and
+ * preparing to return details about the objects loaded into the address space
+ * by the Linux linker.
+ *
+ * When a debug tool asks to know what objects are loaded in the target,
+ * librtld_db walks the Illumos link maps and iterates over each object it
+ * finds there, handing information about each to the tool. It then calls down
+ * into this helper library, which does the same for the brand-specific objects
+ * used by the target.
+ *
+ * This debug-helper code contains a bunch of helpful ps_plog calls. To enable
+ * this output with the ptools (e.g. pmap) set LIBPROC_DEBUG=1 in your
+ * environment. To enable it with mdb set MDB_DEBUG=psvc in your environment.
+ */
+
+/*
+ * ATTENTION:
+ * Librtl_db brand plugin libraries should NOT directly invoke any
+ * libproc.so interfaces or be linked against libproc. If a librtl_db
+ * brand plugin library uses libproc.so interfaces then it may break
+ * any other librtld_db consumers (like mdb) that tries to attach
+ * to a branded process. The only safe interfaces that the a librtld_db
+ * brand plugin library can use to access a target process are the
+ * proc_service(3PROC) apis.
+ */
+
+/*
+ * M_DATA comes from some streams header file but is also redifined in
+ * _rtld_db.h, so nuke the old streams definition here.
+ */
+#ifdef M_DATA
+#undef M_DATA
+#endif /* M_DATA */
+
+/*
+ * For 32-bit versions of this library, this file gets compiled once.
+ * For 64-bit versions of this library, this file gets compiled twice,
+ * once with _ELF64 defined and once without. The expectation is that
+ * the 64-bit version of the library can properly deal with both 32-bit
+ * and 64-bit elf files, hence in the 64-bit library there are two copies
+ * of all the interfaces in this file, one set named *32 and one named *64.
+ *
+ * This also means that we need to be careful when declaring local pointers
+ * that point to objects in another processes address space, since these
+ * pointers may not match the current processes pointer width. Basically,
+ * we should avoid using data types that change size between 32 and 64 bit
+ * modes like: long, void *, uintptr_t, caddr_t, psaddr_t, size_t, etc.
+ * Instead we should declare all pointers as uint32_t. Then when we
+ * are compiled to deal with 64-bit targets we'll re-define uint32_t
+ * to be a uint64_t.
+ */
+#ifdef _LP64
+#ifdef _ELF64
+#define lx_ldb_get_dyns32 lx_ldb_get_dyns64
+#define lx_ldb_init32 lx_ldb_init64
+#define lx_ldb_fini32 lx_ldb_fini64
+#define lx_ldb_loadobj_iter32 lx_ldb_loadobj_iter64
+#define lx_ldb_getauxval32 lx_ldb_getauxval64
+#define lx_elf_props32 lx_elf_props64
+#define _rd_get_dyns32 _rd_get_dyns64
+#define _rd_get_ehdr32 _rd_get_ehdr64
+#define uint32_t uint64_t
+#define Elf32_Dyn Elf64_Dyn
+#define Elf32_Ehdr Elf64_Ehdr
+#define Elf32_Phdr Elf64_Phdr
+#define Elf32_Sym Elf64_Sym
+#endif /* _ELF64 */
+#endif /* _LP64 */
+
+/* Included from usr/src/cmd/sgs/librtld_db/common */
+#include <_rtld_db.h>
+
+typedef struct lx_rd {
+ rd_agent_t *lr_rap;
+ struct ps_prochandle *lr_php; /* proc handle pointer */
+ uint32_t lr_rdebug; /* address of lx r_debug */
+ uint32_t lr_exec; /* base address of executable */
+} lx_rd_t;
+
+typedef struct lx_link_map {
+ uint32_t lxm_addr; /* Base address shared object is loaded at. */
+ uint32_t lxm_name; /* Absolute file name object was found in. */
+ uint32_t lxm_ld; /* Dynamic section of the shared object. */
+ uint32_t lxm_next; /* Chain of loaded objects. */
+} lx_link_map_t;
+
+typedef struct lx_r_debug {
+ int r_version; /* Version number for this protocol. */
+ uint32_t r_map; /* Head of the chain of loaded objects. */
+
+ /*
+ * This is the address of a function internal to the run-time linker,
+ * that will always be called when the linker begins to map in a
+ * library or unmap it, and again when the mapping change is complete.
+ * The debugger can set a breakpoint at this address if it wants to
+ * notice shared object mapping changes.
+ */
+ uint32_t r_brk;
+ r_state_e r_state; /* defined the same way between lx/solaris */
+ uint32_t r_ldbase; /* Base address the linker is loaded at. */
+} lx_r_debug_t;
+
+static uint32_t
+lx_ldb_getauxval32(struct ps_prochandle *php, int type)
+{
+ const auxv_t *auxvp = NULL;
+
+ if (ps_pauxv(php, &auxvp) != PS_OK)
+ return ((uint32_t)-1);
+
+ while (auxvp->a_type != AT_NULL) {
+ if (auxvp->a_type == type)
+ return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr);
+ auxvp++;
+ }
+ return ((uint32_t)-1);
+}
+
+/*
+ * A key difference between the linux linker and ours' is that the linux
+ * linker adds the base address of segments to certain values in the
+ * segments' ELF header. As an example, look at the address of the
+ * DT_HASH hash table in a Solaris section - it is a relative address
+ * which locates the start of the hash table, relative to the beginning
+ * of the ELF file. However, when the linux linker loads a section, it
+ * modifies the in-memory ELF image by changing address of the hash
+ * table to be an absolute address. This is only done for libraries - not for
+ * executables.
+ *
+ * Solaris tools expect the relative address to remain relative, so
+ * here we will modify the in-memory ELF image so that it once again
+ * contains relative addresses.
+ *
+ * To accomplish this, we walk through all sections in the target.
+ * Linux sections are identified by pointing to the linux linker or libc in the
+ * DT_NEEDED section. For all matching sections, we subtract the segment
+ * base address to get back to relative addresses.
+ */
+static rd_err_e
+lx_ldb_get_dyns32(rd_helper_data_t rhd,
+ psaddr_t addr, void **dynpp, size_t *dynpp_sz)
+{
+ lx_rd_t *lx_rd = (lx_rd_t *)rhd;
+ rd_agent_t *rap = lx_rd->lr_rap;
+ Elf32_Ehdr ehdr;
+ Elf32_Dyn *dynp = NULL;
+ size_t dynp_sz;
+ uint_t ndyns;
+ int i;
+
+ ps_plog("lx_ldb_get_dyns: invoked for object at 0x%p", addr);
+
+ /* Read in a copy of the ehdr */
+ if (_rd_get_ehdr32(rap, addr, &ehdr, NULL) != RD_OK) {
+ ps_plog("lx_ldb_get_dyns: _rd_get_ehdr() failed");
+ return (RD_ERR);
+ }
+
+ /* read out the PT_DYNAMIC elements for this object */
+ if (_rd_get_dyns32(rap, addr, &dynp, &dynp_sz) != RD_OK) {
+ ps_plog("lx_ldb_get_dyns: _rd_get_dyns() failed");
+ return (RD_ERR);
+ }
+
+ /*
+ * From here on out if we encounter an error we'll just return
+ * success and pass back the unmolested dynamic elements that
+ * we've already obtained.
+ */
+ if (dynpp != NULL)
+ *dynpp = dynp;
+ if (dynpp_sz != NULL)
+ *dynpp_sz = dynp_sz;
+ ndyns = dynp_sz / sizeof (Elf32_Dyn);
+
+ /* If this isn't a dynamic object, there's nothing left todo */
+ if (ehdr.e_type != ET_DYN) {
+ ps_plog("lx_ldb_get_dyns: done: not a shared object");
+ return (RD_OK);
+ }
+
+ /*
+ * Before we blindly start changing dynamic section addresses
+ * we need to figure out if the current object that we're looking
+ * at is a linux object or a solaris object. To do this first
+ * we need to find the string tab dynamic section element.
+ */
+ for (i = 0; i < ndyns; i++) {
+ if (dynp[i].d_tag == DT_STRTAB)
+ break;
+ }
+ if (i == ndyns) {
+ ps_plog("lx_ldb_get_dyns: "
+ "failed to find string tab in the dynamic section");
+ return (RD_OK);
+ }
+
+ /*
+ * Check if the strtab value looks like an offset or an address.
+ * It's an offset if the value is less then the base address that
+ * the object is loaded at, or if the value is less than the offset
+ * of the section headers in the same elf object. This check isn't
+ * perfect, but in practice it's good enough.
+ */
+ if ((dynp[i].d_un.d_ptr < addr) ||
+ (dynp[i].d_un.d_ptr < ehdr.e_shoff)) {
+ ps_plog("lx_ldb_get_dyns: "
+ "doesn't appear to be an lx object");
+ return (RD_OK);
+ }
+
+ /*
+ * This seems to be a a linux object, so we'll patch up the dynamic
+ * section addresses
+ */
+ ps_plog("lx_ldb_get_dyns: "
+ "patching up lx object dynamic section addresses");
+ for (i = 0; i < ndyns; i++) {
+ switch (dynp[i].d_tag) {
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_REL:
+ case DT_DEBUG:
+ case DT_JMPREL:
+ case DT_VERSYM:
+ if (dynp[i].d_un.d_val > addr) {
+ dynp[i].d_un.d_ptr -= addr;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return (RD_OK);
+}
+
+static void
+lx_ldb_fini32(rd_helper_data_t rhd)
+{
+ lx_rd_t *lx_rd = (lx_rd_t *)rhd;
+ ps_plog("lx_ldb_fini: cleaning up lx helper");
+ free(lx_rd);
+}
+
+/*
+ * The linux linker has an r_debug structure somewhere in its data section that
+ * contains the address of the head of the link map list. To find this, we will
+ * use the DT_DEBUG token in the executable's dynamic section. The linux linker
+ * wrote the address of its r_debug structure to the DT_DEBUG dynamic entry. We
+ * get the address of the executable's program headers from the
+ * AT_SUN_BRAND_LX_PHDR aux vector entry. From there, we calculate the
+ * address of the Elf header, and from there we can easily get to the DT_DEBUG
+ * entry.
+ */
+static rd_helper_data_t
+lx_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
+{
+ lx_rd_t *lx_rd;
+ uint32_t addr, phdr_addr, dyn_addr;
+ uint32_t symtab, strtab, offs;
+ uint32_t vaddr, memsz;
+ caddr_t mem;
+ Elf32_Dyn *dyn;
+ Elf32_Phdr phdr, *ph, *dph, *phdrs;
+ Elf32_Ehdr ehdr;
+ Elf32_Sym *sym;
+ int i, dyn_count;
+
+ lx_rd = calloc(sizeof (lx_rd_t), 1);
+ if (lx_rd == NULL) {
+ ps_plog("lx_ldb_init: cannot allocate memory");
+ return (NULL);
+ }
+ lx_rd->lr_rap = rap;
+ lx_rd->lr_php = php;
+
+ phdr_addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_PHDR);
+ if (phdr_addr == (uint32_t)-1) {
+ ps_plog("lx_ldb_init: no LX_PHDR found in aux vector");
+ return (NULL);
+ }
+ ps_plog("lx_ldb_init: found LX_PHDR auxv phdr at: 0x%p",
+ phdr_addr);
+
+ if (ps_pread(php, phdr_addr, &phdr, sizeof (phdr)) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read phdr at 0x%p",
+ phdr_addr);
+ free(lx_rd);
+ return (NULL);
+ }
+
+ /* The ELF header should be before the program header in memory */
+ lx_rd->lr_exec = addr = phdr_addr - phdr.p_offset;
+ if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read ehdr at 0x%p",
+ lx_rd->lr_exec);
+ free(lx_rd);
+ return (NULL);
+ }
+ ps_plog("lx_ldb_init: read ehdr at: 0x%p", addr);
+ ps_plog("lx_ldb_init: ehdr t %d ent 0x%p poff 0x%p psize %d pnum %d",
+ ehdr.e_type, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize,
+ ehdr.e_phnum);
+
+ if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) {
+ ps_plog("lx_ldb_init: couldn't alloc phdrs memory");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ if (ps_pread(php, phdr_addr, phdrs, ehdr.e_phnum * ehdr.e_phentsize) !=
+ PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read phdrs at 0x%p",
+ phdr_addr);
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ /* program headers */
+ ps_plog("lx_ldb_init: read %d phdrs at: 0x%p",
+ ehdr.e_phnum, phdr_addr);
+
+ for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++,
+ /*LINTED */
+ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) {
+ ps_plog("lx_ldb_init: ph[%d] 0x%p type %d", i,
+ (phdr_addr + ((char *)ph - (char *)phdrs)), ph->p_type);
+ if (ph->p_type == PT_DYNAMIC)
+ break;
+ }
+ if (i == ehdr.e_phnum) {
+ ps_plog("lx_ldb_init: no PT_DYNAMIC in executable");
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+ ps_plog("lx_ldb_init: found PT_DYNAMIC phdr[%d] at: 0x%p",
+ i, (phdr_addr + ((char *)ph - (char *)phdrs)));
+ ps_plog("lx_ldb_init: ph t 0x%x f 0x%x o 0x%p v 0x%p s %d",
+ ph->p_type, ph->p_flags, ph->p_offset, ph->p_vaddr, ph->p_filesz);
+
+ if ((dyn = malloc(ph->p_filesz)) == NULL) {
+ ps_plog("lx_ldb_init: couldn't alloc for PT_DYNAMIC");
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ /*
+ * Unclear why the dyn_addr works sometimes with one value and
+ * sometimes for the other, so we handle both cases.
+ */
+
+ dyn_count = ph->p_filesz / sizeof (Elf32_Dyn);
+ ps_plog("lx_ldb_init: dyn_count %d %d", dyn_count, sizeof (Elf32_Dyn));
+ dyn_addr = addr + ph->p_vaddr;
+ ps_plog("lx_ldb_init: dyn_addr 0x%p 0x%x = 0x%p",
+ addr, ph->p_offset, dyn_addr);
+ if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read dynamic at 0x%p, "
+ "trying dyn_addr 0x%p",
+ dyn_addr, ph->p_vaddr);
+
+ dyn_addr = ph->p_vaddr;
+ if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read dynamic at 0x%p",
+ dyn_addr);
+
+ free(lx_rd);
+ free(phdrs);
+ free(dyn);
+ return (NULL);
+ }
+ }
+ ps_plog("lx_ldb_init: read %d dynamic headers at: 0x%p",
+ dyn_count, dyn_addr);
+
+ for (i = 0; i < dyn_count; i++) {
+ if (dyn[i].d_tag == DT_DEBUG) {
+ lx_rd->lr_rdebug = dyn[i].d_un.d_ptr;
+ break;
+ }
+ }
+ free(phdrs);
+ free(dyn);
+
+ if (lx_rd->lr_rdebug != 0) {
+ ps_plog("lx_ldb_init: found DT_DEBUG: 0x%p", lx_rd->lr_rdebug);
+ return ((rd_helper_data_t)lx_rd);
+ }
+
+ ps_plog("lx_ldb_init: no DT_DEBUG found in exe; looking for r_debug");
+
+ /*
+ * If we didn't find DT_DEBUG, we're going to employ the same fallback
+ * as gdb: pawing through the dynamic linker's symbol table looking
+ * for the r_debug symbol.
+ */
+ addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_INTERP);
+
+ if (addr == (uint32_t)-1) {
+ ps_plog("lx_ldb_init: no interpreter; failing");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ ps_plog("lx_ldb_init: reading interp ehdr at 0x%p", addr);
+
+ if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read interp ehdr at 0x%p", addr);
+ free(lx_rd);
+ return (NULL);
+ }
+
+ if (ehdr.e_type != ET_DYN) {
+ ps_plog("lx_ldb_init: interp ehdr not of type ET_DYN");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ phdr_addr = addr + ehdr.e_phoff;
+
+ if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) {
+ ps_plog("lx_ldb_init: couldn't alloc interp phdrs memory");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ if (ps_pread(php, phdr_addr, phdrs,
+ ehdr.e_phnum * ehdr.e_phentsize) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read interp phdrs at 0x%p",
+ phdr_addr);
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ ps_plog("lx_ldb_init: read %d interp phdrs at: 0x%p",
+ ehdr.e_phnum, phdr_addr);
+
+ vaddr = (uint32_t)-1;
+ memsz = 0;
+
+ for (i = 0, ph = phdrs, dph = NULL; i < ehdr.e_phnum; i++,
+ /*LINTED */
+ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) {
+ /*
+ * Keep track of our lowest PT_LOAD address, as this segment
+ * contains the DT_SYMTAB and DT_STRTAB.
+ */
+ if (ph->p_type == PT_LOAD && ph->p_vaddr < vaddr) {
+ vaddr = ph->p_vaddr;
+ memsz = ph->p_memsz;
+ }
+
+ if (ph->p_type == PT_DYNAMIC)
+ dph = ph;
+ }
+
+ if (vaddr == (uint32_t)-1 || memsz == 0) {
+ ps_plog("lx_ldb_init: no PT_LOAD section in interp");
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ ps_plog("lx_ldb_init: found interp PT_LOAD to be %d bytes at 0x%p",
+ memsz, vaddr);
+
+ if ((ph = dph) == NULL) {
+ ps_plog("lx_ldb_init: no PT_DYNAMIC in interp");
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ ps_plog("lx_ldb_init: found interp PT_DYNAMIC phdr[%d] at: 0x%p",
+ i, (phdr_addr + ((char *)ph - (char *)phdrs)));
+
+ if ((dyn = malloc(ph->p_filesz)) == NULL) {
+ ps_plog("lx_ldb_init: couldn't alloc for interp PT_DYNAMIC");
+ free(lx_rd);
+ free(phdrs);
+ return (NULL);
+ }
+
+ dyn_addr = addr + ph->p_offset;
+ dyn_count = ph->p_filesz / sizeof (Elf32_Dyn);
+
+ if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read interp dynamic at 0x%p",
+ dyn_addr);
+ free(lx_rd);
+ free(phdrs);
+ free(dyn);
+ return (NULL);
+ }
+
+ free(phdrs);
+
+ ps_plog("lx_ldb_init: read %d interp dynamic headers at: 0x%p",
+ dyn_count, dyn_addr);
+
+ /*
+ * As noted in lx_ldb_get_dyns32(), in Linux, the PT_DYNAMIC table
+ * is adjusted to represent absolute addresses instead of offsets.
+ * This is not true for the interpreter, however -- where the values
+ * will be represented as offsets from the lowest PT_LOAD p_vaddr.
+ */
+ symtab = strtab = (uint32_t)-1;
+
+ for (i = 0; i < dyn_count; i++) {
+ if (dyn[i].d_tag == DT_STRTAB)
+ strtab = dyn[i].d_un.d_ptr - vaddr;
+
+ if (dyn[i].d_tag == DT_SYMTAB)
+ symtab = dyn[i].d_un.d_ptr - vaddr;
+ }
+
+ free(dyn);
+
+ if (strtab == (uint32_t)-1 || strtab > memsz) {
+ ps_plog("lx_ldb_init: didn't find valid interp strtab");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ if (symtab == (uint32_t)-1 || symtab > memsz) {
+ ps_plog("lx_ldb_init: didn't find valid interp symtab");
+ free(lx_rd);
+ return (NULL);
+ }
+
+ ps_plog("lx_ldb_init: strtab is 0x%p, symtab is 0x%p",
+ addr + strtab, addr + symtab);
+
+ if ((mem = malloc(memsz)) == NULL) {
+ ps_plog("lx_ldb_init: couldn't allocate interp "
+ "buffer of 0x%p bytes", memsz);
+ free(lx_rd);
+ return (NULL);
+ }
+
+ if (ps_pread(php, addr, mem, memsz) != PS_OK) {
+ ps_plog("lx_ldb_init: couldn't read interp at 0x%p", addr);
+ free(lx_rd);
+ free(mem);
+ return (NULL);
+ }
+
+ /*
+ * We make an assumption that is made elsewhere in the Linux linker:
+ * that the DT_SYMTAB immediately precedes the DT_STRTAB.
+ */
+ for (offs = symtab; offs < strtab; offs += sizeof (Elf32_Sym)) {
+ uint32_t p;
+
+ sym = (Elf32_Sym *)&mem[offs];
+
+ if (sym->st_name > memsz) {
+ ps_plog("lx_ldb_init: invalid st_name at sym 0x%p",
+ addr + offs);
+ continue;
+ }
+
+ p = sym->st_name;
+
+ if (strtab + p > memsz) {
+ ps_plog("lx_ldb_init: invalid symbol address 0x%p, "
+ "memsz 0x%p", strtab + p, memsz);
+ continue;
+ }
+
+ if (mem[strtab + p] == '\0')
+ continue;
+
+ /* Sometimes we're pointing into the middle of a symbol? */
+ while ((strtab + p) > 0 && (strtab + p) < memsz &&
+ mem[strtab + p] != '\0')
+ p--;
+ p++;
+
+ ps_plog("lx_ldb_init: interp symbol (0x%p) %s",
+ strtab + p, &mem[strtab + p]);
+
+ if (strcmp(&mem[strtab + p], "_r_debug") == 0)
+ break;
+ }
+
+ if (offs >= strtab) {
+ ps_plog("lx_ldb_init: no _r_debug found in interpreter");
+ free(mem);
+ free(lx_rd);
+ return (NULL);
+ }
+
+ lx_rd->lr_rdebug = (sym->st_value - vaddr) + addr;
+ ps_plog("lx_ldb_init: found _r_debug at 0x%p", lx_rd->lr_rdebug);
+ free(mem);
+
+ return ((rd_helper_data_t)lx_rd);
+}
+
+/*
+ * Given the address of an ELF object in the target, return its size and
+ * the proper link map ID.
+ */
+static size_t
+lx_elf_props32(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr)
+{
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr *phdrs, *ph;
+ int i;
+ uint32_t min = (uint32_t)-1;
+ uint32_t max = 0;
+ size_t sz = NULL;
+
+ if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) {
+ ps_plog("lx_elf_props: Couldn't read ELF header at 0x%p",
+ addr);
+ return (0);
+ }
+
+ if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL)
+ return (0);
+
+ if (ps_pread(php, addr + ehdr.e_phoff, phdrs, ehdr.e_phnum *
+ ehdr.e_phentsize) != PS_OK) {
+ ps_plog("lx_elf_props: Couldn't read program headers at 0x%p",
+ addr + ehdr.e_phoff);
+ return (0);
+ }
+
+ for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++,
+ /*LINTED */
+ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) {
+
+ if (ph->p_type != PT_LOAD)
+ continue;
+
+ if ((ph->p_flags & (PF_W | PF_R)) == (PF_W | PF_R)) {
+ *data_addr = ph->p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ *data_addr += addr;
+ if (*data_addr & (ph->p_align - 1))
+ *data_addr = *data_addr & (~(ph->p_align -1));
+ }
+
+ if (ph->p_vaddr < min)
+ min = ph->p_vaddr;
+
+ if (ph->p_vaddr > max) {
+ max = ph->p_vaddr;
+ sz = ph->p_memsz + max - min;
+ if (sz & (ph->p_align - 1))
+ sz = (sz & (~(ph->p_align - 1))) + ph->p_align;
+ }
+ }
+
+ free(phdrs);
+ return (sz);
+}
+
+static int
+lx_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
+{
+ lx_rd_t *lx_rd = (lx_rd_t *)rhd;
+ struct ps_prochandle *php = lx_rd->lr_php;
+ lx_r_debug_t r_debug;
+ lx_link_map_t map;
+ uint32_t p = NULL;
+ int rc;
+ rd_loadobj_t exec;
+
+ if ((rc = ps_pread(php, (psaddr_t)lx_rd->lr_rdebug, &r_debug,
+ sizeof (r_debug))) != PS_OK) {
+ ps_plog("lx_ldb_loadobj_iter: "
+ "Couldn't read linux r_debug at 0x%p", lx_rd->lr_rdebug);
+ return (rc);
+ }
+
+ p = r_debug.r_map;
+
+ /*
+ * The first item on the link map list is for the executable, but it
+ * doesn't give us any useful information about it. We need to
+ * synthesize a rd_loadobj_t for the client.
+ *
+ * Linux doesn't give us the executable name, so we'll get it from
+ * the AT_EXECNAME entry instead.
+ */
+ if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) {
+ ps_plog("lx_ldb_loadobj_iter: "
+ "Couldn't read linux link map at 0x%p", p);
+ return (rc);
+ }
+
+ bzero(&exec, sizeof (exec));
+ exec.rl_base = lx_rd->lr_exec;
+ exec.rl_dynamic = map.lxm_ld;
+ exec.rl_nameaddr = lx_ldb_getauxval32(php, AT_SUN_EXECNAME);
+ exec.rl_lmident = LM_ID_BASE;
+
+ exec.rl_bend = exec.rl_base +
+ lx_elf_props32(php, lx_rd->lr_exec, &exec.rl_data_base);
+
+ if ((*cb)(&exec, client_data) == 0) {
+ ps_plog("lx_ldb_loadobj_iter: "
+ "client callb failed for executable");
+ return (PS_ERR);
+ }
+ ps_plog("lx_ldb_loadobj_iter: exec base 0x%p dyn 0x%p",
+ exec.rl_base, exec.rl_dynamic);
+
+ for (p = map.lxm_next; p != NULL; p = map.lxm_next) {
+ rd_loadobj_t obj;
+
+ if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) !=
+ PS_OK) {
+ ps_plog("lx_ldb_loadobj_iter: "
+ "Couldn't read lk map at %p", p);
+ return (rc);
+ }
+
+ /*
+ * The linux link map has less information than the Solaris one.
+ * We need to go fetch the missing information from the ELF
+ * headers.
+ */
+
+ obj.rl_nameaddr = (psaddr_t)map.lxm_name;
+ obj.rl_base = map.lxm_addr;
+ obj.rl_refnameaddr = (psaddr_t)map.lxm_name;
+ obj.rl_plt_base = NULL;
+ obj.rl_plt_size = 0;
+ obj.rl_lmident = LM_ID_BASE;
+
+ ps_plog("lx_ldb_loadobj_iter: map base 0x%p 0x%p",
+ obj.rl_base, obj.rl_nameaddr);
+
+ /*
+ * Ugh - we have to walk the ELF stuff, find the PT_LOAD
+ * sections, and calculate the end of the file's mappings
+ * ourselves.
+ */
+
+ obj.rl_bend = map.lxm_addr +
+ lx_elf_props32(php, map.lxm_addr, &obj.rl_data_base);
+ obj.rl_padstart = obj.rl_base;
+ obj.rl_padend = obj.rl_bend;
+ obj.rl_dynamic = map.lxm_ld;
+ obj.rl_tlsmodid = 0;
+
+ ps_plog("lx_ldb_loadobj_iter: 0x%p to 0x%p",
+ obj.rl_base, obj.rl_bend);
+
+ if ((*cb)(&obj, client_data) == 0) {
+ ps_plog("lx_ldb_loadobj_iter: "
+ "Client callback failed on %s", map.lxm_name);
+ return (rc);
+ }
+ }
+ return (RD_OK);
+}
+
+/*
+ * Librtld_db plugin linkage struct.
+ *
+ * When we get loaded by librtld_db, it will look for the symbol below
+ * to find our plugin entry points.
+ */
+rd_helper_ops_t RTLD_DB_BRAND_OPS = {
+ LM_ID_BRAND,
+ lx_ldb_init32,
+ lx_ldb_fini32,
+ lx_ldb_loadobj_iter32,
+ lx_ldb_get_dyns32
+};
diff --git a/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers b/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers
new file mode 100644
index 0000000000..5e328d6075
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/common/mapfile-vers
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+{
+ global:
+ rtld_db_brand_ops32;
+ local:
+ *;
+};
+
+#Externally defined symbols
+{
+ global:
+ ps_pauxv = NODIRECT PARENT;
+ ps_pdmodel = NODIRECT PARENT;
+ ps_pglobal_lookup = NODIRECT PARENT;
+ ps_pglobal_sym = NODIRECT PARENT;
+ ps_plog = NODIRECT PARENT;
+ ps_pread = NODIRECT PARENT;
+ ps_pwrite = NODIRECT PARENT;
+};
diff --git a/usr/src/lib/brand/lx/librtld_db/i386/Makefile b/usr/src/lib/brand/lx/librtld_db/i386/Makefile
new file mode 100644
index 0000000000..b5f780c072
--- /dev/null
+++ b/usr/src/lib/brand/lx/librtld_db/i386/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+CLOBBERFILES = $(ROOTLIBDIR)/$(DYNLIB)
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/brand/lx/lx_brand/Makefile b/usr/src/lib/brand/lx/lx_brand/Makefile
new file mode 100644
index 0000000000..fc217b672c
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../../../Makefile.lib
+
+default: all
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/brand/lx/lx_brand/Makefile.com b/usr/src/lib/brand/lx/lx_brand/Makefile.com
new file mode 100644
index 0000000000..a959ae604a
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/Makefile.com
@@ -0,0 +1,100 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2017 Joyent, Inc.
+#
+
+LX_CMN = $(SRC)/common/brand/lx
+
+LIBRARY = lx_brand.a
+VERS = .1
+COBJS = capabilities.o \
+ clock.o \
+ clone.o \
+ debug.o \
+ dir.o \
+ file.o \
+ fcntl.o \
+ fork.o \
+ lx_brand.o \
+ mem.o \
+ misc.o \
+ module.o \
+ mount.o \
+ mount_nfs.o \
+ ptrace.o \
+ sendfile.o \
+ signal.o \
+ stack.o \
+ statfs.o \
+ sysctl.o \
+ sysv_ipc.o \
+ time.o \
+ truncate.o
+
+CMNOBJS = lx_auxv.o \
+ lx_errno.o \
+ lx_signum.o
+ASOBJS = lx_handler.o lx_crt.o
+OBJECTS = $(CMNOBJS) $(COBJS) $(ASOBJS)
+
+USDT_PROVIDERS = lx_provider.d
+
+include ../../Makefile.lx
+include ../../../../Makefile.lib
+
+CSRCS = $(COBJS:%o=../common/%c) $(CMNOBJS:%o=$(LX_CMN)/%c)
+ASSRCS = $(ASOBJS:%o=$(ISASRCDIR)/%s)
+SRCS = $(CSRCS) $(ASSRCS)
+
+SRCDIR = ../common
+UTSBASE = ../../../../../uts
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lsocket -lmapmalloc -lproc -lrtld_db -lrpcsvc -lnsl
+DYNFLAGS += $(DYNFLAGS_$(CLASS))
+DYNFLAGS += $(BLOCAL) $(ZNOVERSION) -Wl,-e_start -M../common/mapfile
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I. -I../ -I$(UTSBASE)/common/brand/lx -I$(LX_CMN)
+ASFLAGS = -P $(ASFLAGS_$(CURTYPE)) -D_ASM -I../ \
+ -I$(UTSBASE)/common/brand/lx
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../../Makefile.targ
+include ../../../../Makefile.usdt
+
+pics/%.o: $(ISASRCDIR)/%.s
+ $(COMPILE.s) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: $(LX_CMN)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/brand/lx/lx_brand/amd64/Makefile b/usr/src/lib/brand/lx/lx_brand/amd64/Makefile
new file mode 100644
index 0000000000..a1db90cd38
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/amd64/Makefile
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
+#
+#
+# lib/brand/lx/amd64/Makefile
+
+ISASRCDIR=.
+
+ASFLAGS += -P -D_ASM
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+DYNFLAGS += -Wl,-I/native/lib/64/ld.so.1
+CPPFLAGS += -D_SYSCALL32
+
+POFILE= lx_brand.po
+MSGFILES= $(CSRCS)
+
+ASSYMDEP_OBJS = lx_handler.o
+
+install: all $(ROOTLIBS64)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/brand/lx/lx_brand/amd64/lx_crt.s b/usr/src/lib/brand/lx/lx_brand/amd64/lx_crt.s
new file mode 100644
index 0000000000..13a88a3d50
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/amd64/lx_crt.s
@@ -0,0 +1,62 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/asm_linkage.h>
+
+#if defined(lint)
+
+void
+_start(void)
+{
+}
+
+#else /* lint */
+
+ /*
+ * C language startup routine for the lx brand shared library.
+ *
+ * That routine expects to be called with the following arguments:
+ * brand_init(int argc, char *argv[], char *envp[])
+ *
+ * There are no arguments explicitly passed to this entry point,
+ * routine, but we do know how our initial stack has been setup by
+ * the kernel. The stack format is documented in:
+ * usr/src/cmd/sgs/rtld/amd64/boot.s
+ *
+ * So this routine will troll through the stack to setup the argument
+ * values for the common brand library startup routine and then invoke
+ * it. This routine is modeled after the default crt1.s`_start()
+ * routines.
+ */
+ ENTRY_NP(_start)
+ pushq $0 / Build a stack frame. retpc = NULL
+ pushq $0 / fp = NULL
+ movq %rsp, %rbp / first stack frame
+
+ /*
+ * Calculate the location of the envp array by adding the size of
+ * the argv array to the start of the argv array.
+ */
+ movq 16(%rbp), %rdi / argc in %rdi (1st param)
+ leaq 24(%rbp), %rsi / &argv[0] in %rsi (2nd param)
+ leaq 32(%rbp,%rdi,8), %rdx / envp in %rdx (3rd param)
+ call lx_init
+
+ /* lx_init will never return. */
+ /*NOTREACHED*/
+ SET_SIZE(_start)
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_brand/amd64/lx_handler.s b/usr/src/lib/brand/lx/lx_brand/amd64/lx_handler.s
new file mode 100644
index 0000000000..a01d66554d
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/amd64/lx_handler.s
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/regset.h>
+#include <sys/segments.h>
+#include <sys/syscall.h>
+#include <sys/lx_brand.h>
+
+#if defined(_ASM)
+#include <sys/lx_signal.h>
+#include <sys/lx_syscall.h>
+#endif /* _ASM */
+
+/* 64-bit signal syscall numbers */
+#define LX_SYS_rt_sigreturn 15
+
+#if defined(lint)
+
+#include <sys/types.h>
+#include <sys/regset.h>
+#include <sys/signal.h>
+
+void
+lx_rt_sigreturn_tramp(void)
+{}
+
+#else /* lint */
+
+ /*
+ * Trampoline code is called by the return at the end of a Linux
+ * signal handler to return control to the interrupted application
+ * via the lx_rt_sigreturn() syscall.
+ */
+ ENTRY_NP(lx_rt_sigreturn_tramp)
+ movq $LX_SYS_rt_sigreturn, %rax
+ syscall
+ SET_SIZE(lx_rt_sigreturn_tramp)
+
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_brand/common/capabilities.c b/usr/src/lib/brand/lx/lx_brand/common/capabilities.c
new file mode 100644
index 0000000000..ba6b587a92
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/capabilities.c
@@ -0,0 +1,516 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * LX Brand emulation of capget/capset syscalls
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/debug.h>
+#include <sys/lx_types.h>
+#include <sys/lx_syscall.h>
+#include <sys/syscall.h>
+#include <alloca.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/lx_misc.h>
+#include <priv.h>
+
+typedef struct {
+ uint32_t version;
+ int pid;
+} lx_cap_user_header_t;
+
+typedef struct {
+ uint32_t effective;
+ uint32_t permitted;
+ uint32_t inheritable;
+} lx_cap_user_data_t;
+
+typedef struct {
+ priv_set_t *p_effective;
+ priv_set_t *p_permitted;
+ priv_set_t *p_inheritable;
+} lx_cap_privs_t;
+
+#define LX_CAP_UPDATE_PERMITTED 0x1
+#define LX_CAP_UPDATE_EFFECTIVE 0x2
+#define LX_CAP_UPDATE_INHERITABLE 0x4
+
+
+#define LX_CAP_MAXLEN 2
+
+typedef struct {
+ uint32_t effective[LX_CAP_MAXLEN];
+ uint32_t permitted[LX_CAP_MAXLEN];
+ uint32_t inheritable[LX_CAP_MAXLEN];
+} lx_cap_data_t;
+
+#define LX_CAP_VERSION_1 0x19980330
+#define LX_CAP_VERSION_2 0x20071026 /* deprecated by Linux */
+#define LX_CAP_VERSION_3 0x20080522
+
+#define LX_CAP_SETPCAP 8
+
+/*
+ * Even though we lack mappings for capabilities higher than LX_CAP_MAX_VALID,
+ * it's valuable to test all the way out to the end of the second field. This
+ * ensures that new capabilities we lack support for are not silently accepted.
+ */
+#define LX_CAP_MAX_CHECK 63
+
+#define LX_CAP_CAPISSET(id, cap) \
+ (((id < 32) && (((0x1 << id) & cap[0]) != 0)) || \
+ ((id >= 32) && (((0x1 << (id - 32) & cap[1]) != 0))))
+
+#define LX_CAP_CAPSET(id, cap) \
+ if (id < 32) { cap[0] |= (0x1 << id); } \
+ else { cap[1] |= (0x1 << (id - 32)); }
+
+static const char *lx_cap_map_chown[] = {
+ PRIV_FILE_CHOWN,
+ PRIV_FILE_CHOWN_SELF,
+ NULL
+};
+static const char *lx_cap_map_dac_override[] = {
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_WRITE,
+ PRIV_FILE_DAC_EXECUTE,
+ NULL
+};
+static const char *lx_cap_map_dac_read_search[] = {
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_READ,
+ NULL
+};
+static const char *lx_cap_map_fowner[] = { PRIV_FILE_OWNER, NULL };
+static const char *lx_cap_map_fsetid[] = { PRIV_FILE_SETID, NULL };
+static const char *lx_cap_map_kill[] = { PRIV_PROC_OWNER, NULL };
+/*
+ * One way that Linux capabilities(7) differs from Illumos privileges(5) is
+ * that it distinguishes between setuid and setgroups rights. This will be a
+ * problem if an lx-branded process requests to drop only CAP_SETUID but not
+ * CAP_SETGID.
+ *
+ * In that case, CAP_SETUID will be maintained.
+ */
+static const char *lx_cap_map_setgid[] = { PRIV_PROC_SETID, NULL };
+static const char *lx_cap_map_setuid[] = { PRIV_PROC_SETID, NULL };
+static const char *lx_cap_map_linux_immutable[] = { PRIV_FILE_FLAG_SET, NULL };
+static const char *lx_cap_map_bind_service[] = { PRIV_NET_PRIVADDR, NULL };
+static const char *lx_cap_map_net_admin[] = {
+ PRIV_SYS_IP_CONFIG,
+ NULL
+ /*
+ * It would probably make sense to include PRIV_SYS_DL_CONFIG, but that
+ * privilege is not extended to non-global zones by default. A more
+ * sophisticated capabilities translation layer could make it optional.
+ */
+};
+static const char *lx_cap_map_net_raw[] = {
+ PRIV_NET_RAWACCESS,
+ PRIV_NET_ICMPACCESS,
+ NULL
+};
+static const char *lx_cap_map_ipc_lock[] = { PRIV_PROC_LOCK_MEMORY, NULL };
+static const char *lx_cap_map_ipc_owner[] = {
+ PRIV_IPC_DAC_READ,
+ PRIV_IPC_DAC_WRITE,
+ PRIV_IPC_OWNER,
+ NULL
+};
+static const char *lx_cap_map_sys_chroot[] = { PRIV_PROC_CHROOT, NULL };
+static const char *lx_cap_map_sys_admin[] = {
+ PRIV_SYS_MOUNT,
+ PRIV_SYS_ADMIN,
+ NULL
+};
+static const char *lx_cap_map_sys_nice[] = { PRIV_PROC_PRIOUP, NULL };
+static const char *lx_cap_map_sys_resource[] = { PRIV_SYS_RESOURCE, NULL };
+static const char *lx_cap_map_audit_write[] = { PRIV_PROC_AUDIT, NULL };
+static const char *lx_cap_map_audit_control[] = { PRIV_SYS_AUDIT, NULL };
+
+/*
+ * Mapping of Linux capabilities -> Illumos privileges
+ * The ID definitions can be found in the Linux sources here:
+ * include/uapi/linux/capability.h
+ *
+ * Order is critical.
+ */
+static const char ** lx_cap_mapping[LX_CAP_MAX_VALID + 1] = {
+ lx_cap_map_chown, /* CAP_CHOWN */
+ lx_cap_map_dac_override, /* CAP_DAC_OVERRIDE */
+ lx_cap_map_dac_read_search, /* CAP_DAC_READ_SEARCH */
+ lx_cap_map_fowner, /* CAP_FOWNER */
+ lx_cap_map_fsetid, /* CAP_FSETID */
+ lx_cap_map_kill, /* CAP_KILL */
+ lx_cap_map_setgid, /* CAP_SETGID */
+ lx_cap_map_setuid, /* CAP_SETUID */
+ NULL, /* CAP_SETPCAP */
+ lx_cap_map_linux_immutable, /* CAP_LINUX_IMMUTABLE */
+ lx_cap_map_bind_service, /* CAP_BIND_SERVICE */
+ NULL, /* CAP_BROADCAST */
+ lx_cap_map_net_admin, /* CAP_NET_ADMIN */
+ lx_cap_map_net_raw, /* CAP_NET_RAW */
+ lx_cap_map_ipc_lock, /* CAP_IPC_LOCK */
+ lx_cap_map_ipc_owner, /* CAP_IPC_OWNER */
+ NULL, /* CAP_MODULE */
+ NULL, /* CAP_RAWIO */
+ lx_cap_map_sys_chroot, /* CAP_SYS_CHROOT */
+ NULL, /* CAP_PTRACE */
+ NULL, /* CAP_PACCT */
+ lx_cap_map_sys_admin, /* CAP_SYS_ADMIN */
+ NULL, /* CAP_BOOT */
+ lx_cap_map_sys_nice, /* CAP_SYS_NICE */
+ lx_cap_map_sys_resource, /* CAP_SYS_RESOURCE */
+ NULL, /* CAP_SYS_TIME */
+ NULL, /* CAP_SYS_TTY_CONFIG */
+ NULL, /* CAP_MKNOD */
+ NULL, /* CAP_LEASE */
+ lx_cap_map_audit_write, /* CAP_AUDIT_WRITE */
+ lx_cap_map_audit_control, /* CAP_AUDIT_CONTROL */
+ NULL, /* CAP_SETFCAP */
+ NULL, /* CAP_MAC_OVERRIDE */
+ NULL, /* CAP_MAC_ADMIN */
+ NULL, /* CAP_SYSLOG */
+ NULL, /* CAP_WAKE_ALARM */
+ NULL /* CAP_BLOCK_SUSPEND */
+};
+
+/* track priv_set_t size, set on entry to lx_capset/lx_capget */
+static unsigned int lx_cap_priv_size = 0;
+
+/* safely allocate priv_set_t triplet on the stack */
+#define LX_CAP_ALLOC_PRIVS(ptr) \
+ { \
+ ptr = SAFE_ALLOCA(sizeof (lx_cap_privs_t) + \
+ (3 * lx_cap_priv_size)); \
+ if (ptr != NULL) { \
+ ptr->p_effective = (priv_set_t *) \
+ ((caddr_t)ptr + sizeof (lx_cap_privs_t)); \
+ ptr->p_permitted = (priv_set_t *) \
+ ((caddr_t)ptr + sizeof (lx_cap_privs_t) + \
+ lx_cap_priv_size);\
+ ptr->p_inheritable = (priv_set_t *) \
+ ((caddr_t)ptr + sizeof (lx_cap_privs_t) + \
+ 2 * lx_cap_priv_size); \
+ } \
+ }
+
+static long
+lx_cap_update_priv(priv_set_t *priv, const uint32_t cap[])
+{
+ int i, j;
+ boolean_t cap_set;
+ boolean_t priv_set;
+ boolean_t updated = B_FALSE;
+ for (i = 0; i <= LX_CAP_MAX_CHECK; i++) {
+ cap_set = LX_CAP_CAPISSET(i, cap);
+ if (lx_cap_mapping[i] == NULL || i > LX_CAP_MAX_VALID) {
+ /* don't allow setting unsupported caps */
+ if (cap_set) {
+ /*
+ * CAP_SETPCAP is a special capability, with
+ * varying behavior, that can be used to
+ * control if the process can change other
+ * process's capabilities, or to control moving
+ * capabilities between sets. For now we ignore
+ * this if its passed in.
+ */
+ if (i == LX_CAP_SETPCAP) {
+ continue;
+ }
+ lx_unsupported("set unsupported capability %d",
+ i);
+ return (-1);
+ } else {
+ continue;
+ }
+ }
+ for (j = 0; lx_cap_mapping[i][j] != NULL; j++) {
+ priv_set = priv_ismember(priv, lx_cap_mapping[i][j]);
+ if (priv_set && !cap_set) {
+ VERIFY0(priv_delset(priv,
+ lx_cap_mapping[i][j]));
+ updated = B_TRUE;
+ } else if (!priv_set && cap_set) {
+ VERIFY0(priv_addset(priv,
+ lx_cap_mapping[i][j]));
+ updated = B_TRUE;
+ }
+ }
+ }
+ if (updated)
+ return (1);
+ else
+ return (0);
+}
+
+static long
+lx_cap_to_priv(lx_cap_data_t *cap, lx_cap_privs_t *priv)
+{
+ long changes = 0;
+ long result;
+
+ result = lx_cap_update_priv(priv->p_permitted, cap->permitted);
+ if (result < 0)
+ return (-1);
+ else if (result > 0)
+ changes |= LX_CAP_UPDATE_PERMITTED;
+
+ result = lx_cap_update_priv(priv->p_effective, cap->effective);
+ if (result < 0)
+ return (-1);
+ else if (result > 0)
+ changes |= LX_CAP_UPDATE_EFFECTIVE;
+
+ result = lx_cap_update_priv(priv->p_inheritable, cap->inheritable);
+ if (result < 0)
+ return (-1);
+ else if (result > 0)
+ changes |= LX_CAP_UPDATE_INHERITABLE;
+
+ return (changes);
+}
+
+static void
+lx_cap_from_priv(const priv_set_t *priv, uint32_t cap[])
+{
+ int i, j;
+ boolean_t valid;
+ (void) memset(cap, '\0', sizeof (uint32_t) * LX_CAP_MAXLEN);
+ for (i = 0; i <= LX_CAP_MAX_VALID; i++) {
+ if (lx_cap_mapping[i] == NULL) {
+ continue;
+ }
+ valid = B_TRUE;
+ for (j = 0; lx_cap_mapping[i][j] != NULL; j++) {
+ if (!priv_ismember(priv,
+ lx_cap_mapping[i][j])) {
+ valid = B_FALSE;
+ }
+ }
+ if (valid) {
+ LX_CAP_CAPSET(i, cap);
+ }
+ }
+}
+
+static long
+lx_cap_read_cap(const lx_cap_user_header_t *uhp, const lx_cap_user_data_t *udp,
+ lx_cap_data_t *cd)
+{
+ lx_cap_user_header_t uh;
+ lx_cap_user_data_t ud_buf;
+ int cap_count;
+ int i;
+
+ if (uucopy(uhp, &uh, sizeof (uh)) != 0)
+ return (-errno);
+
+ switch (uh.version) {
+ case LX_CAP_VERSION_1:
+ cap_count = 1;
+ break;
+ case LX_CAP_VERSION_2:
+ case LX_CAP_VERSION_3:
+ cap_count = 2;
+ break;
+ default:
+ return (-EINVAL);
+ }
+
+ /* Only allow capset on calling process */
+ if (uh.pid != 0 && uh.pid != getpid())
+ return (-EPERM);
+
+ /* zero the struct in case cap_count < 2 */
+ (void) memset(cd, '\0', sizeof (lx_cap_data_t));
+
+ for (i = 0; i < cap_count; i++) {
+ if (uucopy(udp + i, &ud_buf, sizeof (ud_buf)) != 0)
+ return (-errno);
+ cd->permitted[i] = ud_buf.permitted;
+ cd->effective[i] = ud_buf.effective;
+ cd->inheritable[i] = ud_buf.inheritable;
+ }
+ return (0);
+}
+
+long
+lx_capget(uintptr_t p1, uintptr_t p2)
+{
+ const priv_impl_info_t *impl;
+ lx_cap_user_header_t *uhp = (lx_cap_user_header_t *)p1;
+ lx_cap_user_data_t *udp = (lx_cap_user_data_t *)p2;
+ lx_cap_user_header_t uh;
+ lx_cap_privs_t *privs;
+ lx_cap_data_t cd_result;
+ lx_cap_user_data_t cd_buf;
+ int cap_count;
+ int i;
+
+ if (lx_cap_priv_size == 0) {
+ impl = getprivimplinfo();
+ lx_cap_priv_size = sizeof (priv_chunk_t) * impl->priv_setsize;
+ }
+
+ if (uucopy(uhp, &uh, sizeof (uh)) != 0)
+ return (-errno);
+
+ switch (uh.version) {
+ case LX_CAP_VERSION_1:
+ cap_count = 1;
+ break;
+ case LX_CAP_VERSION_2:
+ case LX_CAP_VERSION_3:
+ cap_count = 2;
+ break;
+ default:
+ /*
+ * As per the man page: call will fail with EINVAL and set the
+ * version field of the header to the kernel preferred version
+ * when an unsupported version value is provided.
+ */
+ uh.version = LX_CAP_VERSION_3;
+ if (uucopy(&uh, uhp, sizeof (uh)) != 0)
+ return (-errno);
+ return (-EINVAL);
+ }
+
+ /*
+ * Only allow capget on the calling process.
+ * If a pid is specified, lie about being able to locate it.
+ */
+ if (uh.pid > 0 && uh.pid != getpid())
+ return (-ESRCH);
+ if (uh.pid < 0)
+ return (-EINVAL);
+
+ LX_CAP_ALLOC_PRIVS(privs)
+
+ if (privs == NULL)
+ return (-ENOMEM);
+
+ if (getppriv(PRIV_PERMITTED, privs->p_permitted) != 0)
+ return (-errno);
+ if (getppriv(PRIV_EFFECTIVE, privs->p_effective) != 0)
+ return (-errno);
+ if (getppriv(PRIV_INHERITABLE, privs->p_inheritable) != 0)
+ return (-errno);
+
+ lx_cap_from_priv(privs->p_permitted, cd_result.permitted);
+ lx_cap_from_priv(privs->p_effective, cd_result.effective);
+ lx_cap_from_priv(privs->p_inheritable, cd_result.inheritable);
+
+ /* convert to output format */
+ for (i = 0; i < cap_count; i++) {
+ cd_buf.effective = cd_result.effective[i];
+ cd_buf.permitted = cd_result.permitted[i];
+ cd_buf.inheritable = cd_result.inheritable[i];
+ if (uucopy(&cd_buf, udp + i, sizeof (cd_buf)) != 0)
+ return (-errno);
+ }
+
+ return (0);
+}
+
+long
+lx_capset(uintptr_t p1, uintptr_t p2)
+{
+ const priv_impl_info_t *impl;
+ lx_cap_data_t cd;
+ lx_cap_privs_t *privs;
+ long result;
+
+ if (lx_cap_priv_size == 0) {
+ impl = getprivimplinfo();
+ lx_cap_priv_size = sizeof (priv_chunk_t) * impl->priv_setsize;
+ }
+
+ /* verify header and read in desired capabilities */
+ result = lx_cap_read_cap((lx_cap_user_header_t *)p1,
+ (lx_cap_user_data_t *)p2, &cd);
+ if (result != 0)
+ return (result);
+
+ LX_CAP_ALLOC_PRIVS(privs)
+
+ if (privs == NULL)
+ return (-ENOMEM);
+
+ /* fetch current privs to compare against */
+ if (getppriv(PRIV_PERMITTED, privs->p_permitted) != 0)
+ return (-errno);
+ if (getppriv(PRIV_EFFECTIVE, privs->p_effective) != 0)
+ return (-errno);
+ if (getppriv(PRIV_INHERITABLE, privs->p_inheritable) != 0)
+ return (-errno);
+
+
+ result = lx_cap_to_priv(&cd, privs);
+ if (result < 0)
+ return (-EPERM);
+
+ /* report success if no changes needed */
+ if (result == 0)
+ return (0);
+
+ /* Ensure the effective/inheritable caps aren't > permitted */
+ if (!priv_issubset(privs->p_effective, privs->p_permitted) ||
+ !priv_issubset(privs->p_inheritable, privs->p_permitted))
+ return (-EPERM);
+
+ /*
+ * Here is where things become racy. Linux updates all three
+ * capability sets simultaneously in the capset syscall. In order to
+ * emulate capabilities via privileges, three setppriv operations are
+ * required in sequence. If one or two should fail, there is not a
+ * mechanism to convey the incomplete operation to the caller.
+ *
+ * We do two things to make this less risky:
+ * 1. Verify that both the desired effective and inheritable
+ * sets are subsets of the desired permitted set.
+ * 2. Perform the setppriv of the permitted set first.
+ *
+ * Should the setppriv(permitted) fail, we can safely bail out with an
+ * error. If it succeeds, the setppriv of effective and inheritable
+ * are likely to succeed given that they've been verified legal.
+ *
+ * If the partial error does happen, we'll be forced to report failure
+ * even though the privileges were altered.
+ */
+
+ if ((result & LX_CAP_UPDATE_PERMITTED) != 0) {
+ /* failure here is totally safe */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, privs->p_permitted) != 0)
+ return (-errno);
+ }
+ if ((result & LX_CAP_UPDATE_EFFECTIVE) != 0) {
+ /* failure here is a bummer */
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privs->p_effective) != 0)
+ return (-errno);
+ }
+ if ((result & LX_CAP_UPDATE_EFFECTIVE) != 0) {
+ /* failure here is a major bummer */
+ if (setppriv(PRIV_SET, PRIV_INHERITABLE,
+ privs->p_inheritable) != 0)
+ return (-errno);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/clock.c b/usr/src/lib/brand/lx/lx_brand/common/clock.c
new file mode 100644
index 0000000000..e627df68dc
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/clock.c
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/resource.h>
+#include <sys/timerfd.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+#include <lx_signum.h>
+
+/*
+ * Translating from the Linux clock types to the illumos types is a bit of a
+ * mess.
+ *
+ * Linux uses different values for it clock identifiers, so we have to do basic
+ * translations between the two. Thankfully, both Linux and illumos implement
+ * the same POSIX SUSv3 clock types, so the semantics should be identical.
+ *
+ * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
+ * clock backends currently implemented on illumos. Functions in the kernel
+ * that use the CLOCK_BACKEND macro will return an error for any clock type
+ * that does not exist in the clock_backend array. These functions are
+ * clock_settime, clock_gettime, clock_getres and timer_create.
+ *
+ * For reference, the kernel's clock_backend array looks like this:
+ *
+ * clock_backend[CLOCK_MAX] (6 entries)
+ * 0 __CLOCK_REALTIME0 valid ptr. (obs. same as CLOCK_REALTIME)
+ * 1 CLOCK_VIRTUAL NULL
+ * 2 CLOCK_THREAD_CPUTIME_ID NULL
+ * 3 CLOCK_REALTIME valid ptr.
+ * 4 CLOCK_MONOTONIC (CLOCK_HIGHRES) valid ptr.
+ * 5 CLOCK_PROCESS_CPUTIME_ID NULL
+ */
+
+#define CLOCK_RT_SLOT 0
+
+#define LX_CLOCK_REALTIME 0
+#define LX_CLOCK_MONOTONIC 1
+
+/*
+ * Limits for a minimum interval are enforced when creating timers from the
+ * CLOCK_HIGHRES source. Values below this minimum will be clamped if the
+ * process lacks the proc_clock_highres privilege.
+ */
+static int ltos_clock[] = {
+ CLOCK_REALTIME, /* LX_CLOCK_REALTIME */
+ CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC */
+ CLOCK_PROCESS_CPUTIME_ID, /* LX_CLOCK_PROCESS_CPUTIME_ID */
+ CLOCK_THREAD_CPUTIME_ID, /* LX_CLOCK_THREAD_CPUTIME_ID */
+ CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC_RAW */
+ CLOCK_REALTIME, /* LX_CLOCK_REALTIME_COARSE */
+ CLOCK_HIGHRES /* LX_CLOCK_MONOTONIC_COARSE */
+};
+
+#define LX_CLOCK_MAX (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
+
+
+long
+lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
+ struct timespec *rmtp)
+{
+ int ret = 0;
+ int err;
+ struct timespec rqt, rmt;
+
+ if (clock < 0 || clock >= LX_CLOCK_MAX)
+ return (-EINVAL);
+
+ if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
+ return (-EFAULT);
+
+ /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
+ if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
+ != 0) {
+ if (err != EINTR)
+ return (-err);
+ ret = -EINTR;
+ /*
+ * We fall through in case we have to pass back the remaining
+ * time.
+ */
+ }
+
+ /*
+ * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
+ * non-NULL.
+ */
+ if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
+ (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
+ return (-EFAULT);
+
+ return (ret);
+}
+
+/*ARGSUSED*/
+long
+lx_adjtimex(void *tp)
+{
+ return (-EPERM);
+}
+
+long
+lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
+ struct itimerspec *old_val)
+{
+ return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
+}
+
+long
+lx_timer_gettime(timer_t tid, struct itimerspec *val)
+{
+ return ((timer_gettime(tid, val) < 0) ? -errno : 0);
+}
+
+long
+lx_timer_getoverrun(timer_t tid)
+{
+ int val;
+
+ val = timer_getoverrun(tid);
+ return ((val < 0) ? -errno : val);
+}
+
+long
+lx_timer_delete(timer_t tid)
+{
+ return ((timer_delete(tid) < 0) ? -errno : 0);
+}
+
+long
+lx_timerfd_create(int clockid, int flags)
+{
+ int r;
+
+ /* These are the only two valid values. LTP tests for this. */
+ if (clockid != LX_CLOCK_REALTIME && clockid != LX_CLOCK_MONOTONIC)
+ return (-EINVAL);
+
+ r = timerfd_create(ltos_clock[clockid], flags);
+ /*
+ * As with the eventfd case, we return a slightly less jarring
+ * error condition if we cannot open /dev/timerfd.
+ */
+ if (r == -1 && errno == ENOENT)
+ return (-ENOTSUP);
+
+ return (r == -1 ? -errno : r);
+}
+
+long
+lx_timerfd_settime(int fd, int flags, const struct itimerspec *value,
+ struct itimerspec *ovalue)
+{
+ int r = timerfd_settime(fd, flags, value, ovalue);
+
+ return (r == -1 ? -errno : r);
+}
+
+long
+lx_timerfd_gettime(int fd, struct itimerspec *value)
+{
+ int r = timerfd_gettime(fd, value);
+
+ return (r == -1 ? -errno : r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/clone.c b/usr/src/lib/brand/lx/lx_brand/common/clone.c
new file mode 100644
index 0000000000..b04ee953a3
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/clone.c
@@ -0,0 +1,696 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <thread.h>
+#include <strings.h>
+#include <libintl.h>
+#include <sys/regset.h>
+#include <sys/syscall.h>
+#include <sys/inttypes.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/segments.h>
+#include <signal.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_types.h>
+#include <sys/lx_signal.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_brand.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_thread.h>
+#include <sys/fork.h>
+#include <sys/mman.h>
+#include <sys/debug.h>
+#include <lx_syscall.h>
+
+#define CLONE_VFORK (LX_CLONE_VM | LX_CLONE_VFORK)
+#define CLONE_TD (LX_CLONE_THREAD|LX_CLONE_DETACH)
+
+#define IS_FORK(f) (((f) & SHARED_AS) == 0)
+#define IS_VFORK(f) (((f) & CLONE_VFORK) == CLONE_VFORK)
+
+/*
+ * This is dicey. This seems to be an internal glibc structure, and not
+ * part of any external interface. Thus, it is subject to change without
+ * notice. FWIW, clone(2) itself seems to be an internal (or at least
+ * unstable) interface, since strace(1) shows it differently than the man
+ * page.
+ */
+struct lx_desc
+{
+ uint32_t entry_number;
+ uint32_t base_addr;
+ uint32_t limit;
+ uint32_t seg_32bit:1;
+ uint32_t contents:2;
+ uint32_t read_exec_only:1;
+ uint32_t limit_in_pages:1;
+ uint32_t seg_not_present:1;
+ uint32_t useable:1;
+ uint32_t empty:25;
+};
+
+struct clone_state {
+ void *c_retaddr; /* instr after clone()'s int80 */
+ int c_flags; /* flags to clone(2) */
+ int c_sig; /* signal to send on thread exit */
+ void *c_stk; /* %esp of new thread */
+ void *c_ptidp;
+ struct lx_desc *c_ldtinfo; /* thread-specific segment */
+ void *c_ctidp;
+ ucontext_t c_uc; /* original register state/sigmask */
+ volatile int *c_clone_res; /* pid/error returned to cloner */
+ int c_ptrace_event; /* ptrace(2) event for child stop */
+ void *c_ntv_stk; /* native stack for this thread */
+ size_t c_ntv_stk_sz; /* native stack size */
+ lx_tsd_t *c_lx_tsd; /* tsd area for thread */
+};
+
+long
+lx_exit(uintptr_t p1)
+{
+ int status = (int)p1;
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ /*
+ * If we are a vfork(2)ed child, we need to exit as quickly and
+ * cleanly as possible to avoid corrupting our parent.
+ */
+ if (lx_tsd->lxtsd_is_vforked != 0) {
+ _exit(status);
+ }
+
+ lx_tsd->lxtsd_exit = LX_ET_EXIT;
+ lx_tsd->lxtsd_exit_status = status;
+
+ lx_ptrace_stop_if_option(LX_PTRACE_O_TRACEEXIT, B_FALSE,
+ (ulong_t)status, NULL);
+
+ /*
+ * This thread is exiting. Restore the state of the thread to
+ * what it was before we started running linux code.
+ */
+ (void) setcontext(&lx_tsd->lxtsd_exit_context);
+
+ /*
+ * If we returned from the setcontext(2), something is very wrong.
+ */
+ lx_err_fatal("exit: unable to set exit context: %s", strerror(errno));
+
+ /*NOTREACHED*/
+ return (0);
+}
+
+long
+lx_group_exit(uintptr_t p1)
+{
+ int status = (int)p1;
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ /*
+ * If we are a vfork(2)ed child, we need to exit as quickly and
+ * cleanly as possible to avoid corrupting our parent.
+ */
+ if (lx_tsd->lxtsd_is_vforked != 0) {
+ _exit(status);
+ }
+
+ lx_tsd->lxtsd_exit = LX_ET_EXIT_GROUP;
+ lx_tsd->lxtsd_exit_status = status;
+
+ /*
+ * This thread is exiting. Restore the state of the thread to
+ * what it was before we started running linux code.
+ */
+ (void) setcontext(&lx_tsd->lxtsd_exit_context);
+
+ /*
+ * If we returned from the setcontext(2), something is very wrong.
+ */
+ lx_err_fatal("group_exit: unable to set exit context: %s",
+ strerror(errno));
+
+ /*NOTREACHED*/
+ return (0);
+}
+
+static void *
+clone_start(void *arg)
+{
+ int rval;
+ struct clone_state *cs = (struct clone_state *)arg;
+ lx_tsd_t *lxtsd;
+
+ /*
+ * Let the kernel finish setting up all the needed state for this
+ * new thread.
+ *
+ * We already created the thread using the thr_create(3C) library
+ * call, so most of the work required to emulate lx_clone(2) has
+ * been done by the time we get to this point.
+ */
+ lx_debug("\tre-vectoring to lx kernel module to complete lx_clone()");
+ lx_debug("\tB_HELPER_CLONE(0x%x, 0x%p, 0x%p, 0x%p)",
+ cs->c_flags, cs->c_ptidp, cs->c_ldtinfo, cs->c_ctidp);
+
+ rval = syscall(SYS_brand, B_HELPER_CLONE, cs->c_flags, cs->c_ptidp,
+ cs->c_ldtinfo, cs->c_ctidp);
+
+ /*
+ * At this point the parent is waiting for cs->c_clone_res to go
+ * non-zero to indicate the thread has been cloned. The value set
+ * in cs->c_clone_res will be used for the return value from
+ * clone().
+ */
+ if (rval < 0) {
+ *(cs->c_clone_res) = -errno;
+ lx_debug("\tkernel clone failed, errno %d\n", errno);
+ free(cs->c_lx_tsd);
+ free(cs);
+ return (NULL);
+ }
+
+ /*
+ * Initialize the thread specific data for this thread.
+ */
+ lxtsd = cs->c_lx_tsd;
+ lx_init_tsd(lxtsd);
+ lxtsd->lxtsd_clone_state = cs;
+
+ /*
+ * Install the emulation stack for this thread. Register the
+ * thread-specific data structure with the stack list so that it may be
+ * freed at thread exit or fork(2).
+ */
+ lx_install_stack(cs->c_ntv_stk, cs->c_ntv_stk_sz, lxtsd);
+
+ /*
+ * Let the parent know that the clone has (effectively) been
+ * completed.
+ */
+ *(cs->c_clone_res) = rval;
+
+ /*
+ * We want to load the general registers from this context, restore the
+ * original signal mask, and switch to the BRAND stack. The original
+ * signal mask was saved to the context by lx_clone().
+ */
+ cs->c_uc.uc_flags = UC_CPU | UC_SIGMASK;
+ cs->c_uc.uc_brand_data[0] = (void *)LX_UC_STACK_BRAND;
+
+ /*
+ * New threads will not link into the existing context chain.
+ */
+ cs->c_uc.uc_link = NULL;
+
+ /*
+ * Set stack pointer and entry point for new thread:
+ */
+ LX_REG(&cs->c_uc, REG_SP) = (uintptr_t)cs->c_stk;
+ LX_REG(&cs->c_uc, REG_PC) = (uintptr_t)cs->c_retaddr;
+
+ /*
+ * Return 0 to the child:
+ */
+ LX_REG(&cs->c_uc, REG_R0) = (uintptr_t)0;
+
+ /*
+ * Fire the ptrace(2) event stop in the new thread:
+ */
+ lx_ptrace_stop_if_option(cs->c_ptrace_event, B_TRUE, 0, &cs->c_uc);
+
+ /*
+ * Jump to the Linux process. This call cannot return.
+ */
+ lx_jump_to_linux(&cs->c_uc);
+ /* NOTREACHED */
+}
+
+/*
+ * The way Linux handles stopping for FORK vs. CLONE does not map exactly to
+ * which syscall was used. Instead, it has to do with which signal is set in
+ * the low byte of the clone flag. The only time the CLONE event is emitted is
+ * if the clone signal (the low byte of the flags argument) is set to something
+ * other than SIGCHLD (see the Linux src in kernel/fork.c do_fork() for the
+ * actual code).
+ */
+static int
+ptrace_clone_event(int flags)
+{
+ if (flags & LX_CLONE_VFORK)
+ return (LX_PTRACE_O_TRACEVFORK);
+
+ if ((flags & LX_CSIGNAL) != LX_SIGCHLD)
+ return (LX_PTRACE_O_TRACECLONE);
+
+ return (LX_PTRACE_O_TRACEFORK);
+}
+
+/*
+ * See glibc sysdeps/unix/sysv/linux/x86_64/clone.S code for x64 argument order
+ * and the Linux kernel/fork.c code for the various ways arguments can be passed
+ * to the clone syscall (CONFIG_CLONE_BACKWARDS, et al).
+ */
+long
+lx_clone(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
+{
+ struct clone_state *cs;
+ int flags = (int)p1;
+ void *cldstk = (void *)p2;
+ void *ptidp = (void *)p3;
+#if defined(_LP64)
+ void *ctidp = (void *)p4;
+ struct lx_desc *ldtinfo = (void *)p5;
+#else /* is 32bit */
+ struct lx_desc *ldtinfo = (void *)p4;
+ void *ctidp = (void *)p5;
+#endif
+ thread_t tid;
+ volatile int clone_res;
+ int sig;
+ int rval;
+ int pid;
+ ucontext_t *ucp;
+ sigset_t sigmask, osigmask;
+ int fork_flags = 0;
+ int ptrace_event;
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ if (flags & LX_CLONE_SETTLS) {
+ lx_debug("lx_clone(flags=0x%x stk=0x%p ptidp=0x%p ldt=0x%p "
+ "ctidp=0x%p", flags, cldstk, ptidp, ldtinfo, ctidp);
+ } else {
+ lx_debug("lx_clone(flags=0x%x stk=0x%p ptidp=0x%p)",
+ flags, cldstk, ptidp);
+ }
+
+ /*
+ * Only supported for pid 0 on Linux after version 2.3.21, and
+ * apparently not at all since 2.5.16.
+ */
+ if (flags & LX_CLONE_PID)
+ return (-EINVAL);
+
+ /*
+ * CLONE_THREAD requires CLONE_SIGHAND.
+ *
+ * CLONE_THREAD and CLONE_DETACHED must both be either set or cleared
+ * in kernel 2.4 and prior.
+ * In kernel 2.6 (and later) CLONE_DETACHED was dropped completely, so
+ * we no longer have this requirement.
+ */
+
+ if (flags & CLONE_TD) {
+ if (!(flags & LX_CLONE_SIGHAND))
+ return (-EINVAL);
+ if (strncmp(lx_release, "2.4", 3) == 0 &&
+ (flags & CLONE_TD) != CLONE_TD)
+ return (-EINVAL);
+ }
+
+ if ((flags & LX_CLONE_NS_UNSUP) != 0) {
+ lx_unsupported("clone(2) no namespace support "
+ "(flags:0x%08X)\n", flags);
+ /*
+ * When the "kernel" does not support namespaces, applications
+ * (e.g. chromium) expect EINVAL, not ENOTSUP.
+ */
+ return (-EINVAL);
+ }
+
+ ucp = lx_syscall_regs();
+
+ /* test if pointer passed by user are writable */
+ if (flags & LX_CLONE_PARENT_SETTID) {
+ if (uucopy(ptidp, &pid, sizeof (int)) != 0)
+ return (-EFAULT);
+ if (uucopy(&pid, ptidp, sizeof (int)) != 0)
+ return (-EFAULT);
+ }
+ if (flags & LX_CLONE_CHILD_SETTID) {
+ if (uucopy(ctidp, &pid, sizeof (int)) != 0)
+ return (-EFAULT);
+ if (uucopy(&pid, ctidp, sizeof (int)) != 0)
+ return (-EFAULT);
+ }
+
+ ptrace_event = ptrace_clone_event(flags);
+
+ /*
+ * Inform the in-kernel ptrace(2) subsystem that we are about to
+ * emulate a fork(2), vfork(2) or clone(2) system call.
+ */
+ lx_ptrace_clone_begin(ptrace_event, !!(flags & LX_CLONE_PTRACE), flags);
+
+ /*
+ * Handle a fork(2) operation here. If this is not a fork, a new
+ * thread will be created after this block. We can also create a new
+ * clone-group here (when two or more processes share data represented
+ * by a subset of the SHARED_AS flags, but not a true thread).
+ */
+ if (IS_FORK(flags) || IS_VFORK(flags) || LX_IS_CLONE_GRP(flags)) {
+ if (flags & LX_CLONE_PARENT) {
+ lx_unsupported("clone(2) only supports CLONE_PARENT "
+ "for threads.\n");
+ return (-ENOTSUP);
+ }
+
+ if ((flags & LX_CSIGNAL) == 0)
+ fork_flags |= FORK_NOSIGCHLD;
+
+ /*
+ * Suspend signal delivery, run the stack management prefork
+ * handler and perform the actual fork(2) operation.
+ */
+ _sigoff();
+ lx_stack_prefork();
+ if (flags & LX_CLONE_VFORK) {
+ lx_sighandlers_t saved;
+
+ /*
+ * Because we keep our signal disposition at user-land
+ * (and in memory), we must prevent it from being
+ * clobbered should our vforked child change the
+ * disposition (e.g., via sigaction()) before releasing
+ * the address space. We preserve our disposition by
+ * taking a snapshot of it before the vfork and
+ * restoring it afterwards -- which we can get away
+ * with because we know that we aren't executing
+ * concurrently with our child.
+ */
+ lx_sighandlers_save(&saved);
+ lx_tsd->lxtsd_is_vforked++;
+ rval = vforkx(fork_flags);
+ if (rval != 0) {
+ lx_tsd->lxtsd_is_vforked--;
+ lx_sighandlers_restore(&saved);
+ }
+ } else {
+ rval = forkx(fork_flags);
+ }
+
+ /*
+ * The parent process returns through the regular system call
+ * path here.
+ */
+ if (rval != 0) {
+ /*
+ * Run the stack management postfork handler in the
+ * parent. In the CLONE_VFORK case, where it only
+ * needs to be performed once due to the shared address
+ * space, it is critical that this step is performed in
+ * the parent and not the child. The latter can result
+ * in un-woken threads blocked on lx_stack_list_lock.
+ */
+ lx_stack_postfork();
+
+ /*
+ * Since we've already forked, we can't do much if
+ * uucopy fails, so we just ignore failure. Failure is
+ * unlikely since we've tested the memory before we did
+ * the fork.
+ */
+ if (rval > 0 && (flags & LX_CLONE_PARENT_SETTID)) {
+ (void) uucopy(&rval, ptidp, sizeof (int));
+ }
+
+ if (rval > 0) {
+ lx_ptrace_stop_if_option(ptrace_event, B_FALSE,
+ (ulong_t)rval, NULL);
+ }
+
+ /*
+ * Re-enable signal delivery in the parent process.
+ */
+ _sigon();
+
+ return ((rval < 0) ? -errno : rval);
+ }
+
+ /*
+ * The rest of this block runs only within the new child
+ * process.
+ */
+
+ if (!IS_VFORK(flags)) {
+ /*
+ * For non-vfork children run the stack management
+ * postfork handler.
+ */
+ lx_stack_postfork();
+
+ /*
+ * We must free the stacks and thread-specific data
+ * objects for every thread except the one duplicated
+ * from the parent by forkx().
+ */
+ lx_free_other_stacks();
+ }
+
+ if (rval == 0 && (flags & LX_CLONE_CHILD_SETTID)) {
+ /*
+ * lx_getpid should not fail, and if it does, there's
+ * not much we can do about it since we've already
+ * forked, so on failure, we just don't copy the
+ * memory.
+ */
+ pid = syscall(SYS_brand, B_GETPID);
+ if (pid >= 0)
+ (void) uucopy(&pid, ctidp, sizeof (int));
+ }
+
+ /*
+ * Set up additional data in the lx_proc_data structure as
+ * necessary.
+ */
+ if ((rval = syscall(SYS_brand, B_HELPER_CLONE, flags, ptidp,
+ ldtinfo, ctidp)) < 0) {
+ return (rval);
+ }
+
+ if (IS_VFORK(flags)) {
+ ucontext_t vforkuc;
+
+ /*
+ * The vfork(2) interface is somewhat less than ideal.
+ * The unfortunate notion of borrowing the address
+ * space of the parent process requires us to jump
+ * through several hoops to prevent corrupting parent
+ * emulation state.
+ *
+ * When returning in the child, we make a copy of the
+ * system call return context and discard three pages
+ * of the native stack. Returning normally would
+ * clobber the native stack frame in which the brand
+ * library in the parent process is presently waiting.
+ *
+ * The calling program is expected to correctly use
+ * this dusty, underspecified relic. Neglecting to
+ * immediately call execve(2) or exit(2) is not
+ * cricket; this stack space will be permanently lost,
+ * not to mention myriad other undefined behaviour.
+ */
+ bcopy(ucp, &vforkuc, sizeof (vforkuc));
+ vforkuc.uc_brand_data[1] =
+ (caddr_t)vforkuc.uc_brand_data[1] -
+ LX_NATIVE_STACK_VFORK_GAP;
+ vforkuc.uc_link = NULL;
+
+ lx_debug("\tvfork native stack sp %p",
+ vforkuc.uc_brand_data[1]);
+
+ /*
+ * If provided, the child needs its new stack set up.
+ */
+ if (cldstk != 0) {
+ lx_debug("\tvfork cldstk %p", cldstk);
+ LX_REG(&vforkuc, REG_SP) = (uintptr_t)cldstk;
+ }
+
+ /*
+ * Stop for ptrace if required.
+ */
+ lx_ptrace_stop_if_option(ptrace_event, B_TRUE, 0, NULL);
+
+ /*
+ * Return to the child via the specially constructed
+ * vfork(2) context.
+ */
+ LX_EMULATE_RETURN(&vforkuc, LX_SYS_clone, 0, 0);
+ (void) syscall(SYS_brand, B_EMULATION_DONE, &vforkuc,
+ LX_SYS_clone, 0, 0);
+
+ assert(0);
+ }
+
+ /*
+ * If provided, the child needs its new stack set up.
+ */
+ if (cldstk != 0) {
+ lx_debug("\tcldstk %p", cldstk);
+ LX_REG(ucp, REG_SP) = (uintptr_t)cldstk;
+ }
+
+ /*
+ * Stop for ptrace if required.
+ */
+ lx_ptrace_stop_if_option(ptrace_event, B_TRUE, 0, NULL);
+
+ /*
+ * Re-enable signal delivery in the child process.
+ */
+ _sigon();
+
+ /*
+ * The child process returns via the regular emulated system
+ * call path:
+ */
+ return (0);
+ }
+
+ /*
+ * A supported clone-group was handled above, so now it must be a
+ * true native thread, which means exactly these flags are supported
+ */
+ if (((flags & SHARED_AS) != SHARED_AS)) {
+ lx_unsupported("clone(2) a thread requires that all or none of "
+ "CLONE_VM/FS/FILES/THREAD/SIGHAND be set. (flags:0x%08X)\n",
+ flags);
+ return (-ENOTSUP);
+ }
+
+ if (cldstk == NULL) {
+ lx_unsupported("clone(2) requires the caller to allocate the "
+ "child's stack.\n");
+ return (-ENOTSUP);
+ }
+
+ /*
+ * If we want a signal-on-exit, ensure that the signal is valid.
+ */
+ if ((sig = ltos_signo[flags & LX_CSIGNAL]) == -1) {
+ lx_unsupported("clone(2) passed unsupported signal: %d", sig);
+ return (-ENOTSUP);
+ }
+
+ /*
+ * Initialise the state structure we pass as an argument to the new
+ * thread:
+ */
+ if ((cs = malloc(sizeof (*cs))) == NULL) {
+ lx_debug("could not allocate clone_state: %s", strerror(errno));
+ return (-ENOMEM);
+ }
+ cs->c_flags = flags;
+ cs->c_sig = sig;
+ cs->c_stk = cldstk;
+ cs->c_ptidp = ptidp;
+ cs->c_ldtinfo = ldtinfo;
+ cs->c_ctidp = ctidp;
+ cs->c_clone_res = &clone_res;
+ cs->c_ptrace_event = ptrace_event;
+ /*
+ * We want the new thread to return directly to the call site for
+ * the system call.
+ */
+ cs->c_retaddr = (void *)LX_REG(ucp, REG_PC);
+ /*
+ * Copy the saved context for the clone(2) system call so that the
+ * new thread may use it to initialise registers.
+ */
+ bcopy(ucp, &cs->c_uc, sizeof (cs->c_uc));
+ if ((cs->c_lx_tsd = malloc(sizeof (*cs->c_lx_tsd))) == NULL) {
+ free(cs);
+ return (-ENOMEM);
+ }
+
+ clone_res = 0;
+
+ /*
+ * Block all signals because the thread we create won't be able to
+ * properly handle them until it's fully set up.
+ */
+ VERIFY0(sigfillset(&sigmask));
+ if (sigprocmask(SIG_BLOCK, &sigmask, &osigmask) < 0) {
+ lx_debug("lx_clone sigprocmask() failed: %s", strerror(errno));
+ free(cs->c_lx_tsd);
+ free(cs);
+ return (-errno);
+ }
+ cs->c_uc.uc_sigmask = osigmask;
+
+ /*
+ * Allocate the native stack for this new thread now, so that we
+ * can return failure gracefully as ENOMEM.
+ */
+ if (lx_alloc_stack(&cs->c_ntv_stk, &cs->c_ntv_stk_sz) != 0) {
+ free(cs->c_lx_tsd);
+ free(cs);
+ return (-ENOMEM);
+ }
+
+ rval = thr_create(NULL, NULL, clone_start, cs, THR_DETACHED, &tid);
+
+ /*
+ * If the thread did not start, free the resources we allocated:
+ */
+ if (rval != 0) {
+ (void) munmap(cs->c_ntv_stk, cs->c_ntv_stk_sz);
+ free(cs->c_lx_tsd);
+ free(cs);
+ }
+
+ /*
+ * Release any pending signals
+ */
+ (void) sigprocmask(SIG_SETMASK, &osigmask, NULL);
+
+ /*
+ * Wait for the child to be created and have its tid assigned.
+ */
+ if (rval == 0) {
+ while (clone_res == 0)
+ ;
+
+ rval = clone_res;
+ lx_ptrace_stop_if_option(ptrace_event, B_FALSE, (ulong_t)rval,
+ NULL);
+
+ return (rval);
+ } else {
+ /*
+ * Return the error from thr_create(3C).
+ */
+ return (-rval);
+ }
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/debug.c b/usr/src/lib/brand/lx/lx_brand/common/debug.c
new file mode 100644
index 0000000000..a8f994c43d
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/debug.c
@@ -0,0 +1,171 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <thread.h>
+#include <unistd.h>
+
+#include <sys/modctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <sys/lx_brand.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+
+/* internal debugging state */
+static const char *lx_debug_path = NULL; /* debug output file path */
+static char lx_debug_path_buf[MAXPATHLEN];
+
+int lx_dtrace_lazyload = 1; /* patchable; see below */
+
+void
+lx_debug_init(boolean_t do_dtrace, boolean_t dbg_enable, const char *dbg_file)
+{
+ /*
+ * Our DTrace USDT provider is loaded in our .init section, which is
+ * not run by our e_entry ELF entry point (_start, which calls into
+ * lx_init()). We exploit this to only actually load our USDT provider
+ * if LX_DTRACE is set, assuring that we don't compromise fork()
+ * performance in the (common) case that DTrace of lx_brand.so.1 itself
+ * isn't enabled or desired. (As with all USDT providers, it can always
+ * be loaded by explicitly specifying the full provider name). Note
+ * that we also allow this behavior to be set via a manual override,
+ * lx_dtrace_lazyload -- allowing for USDT probes to be automatically
+ * provided in situations where setting an environment variable is
+ * tedious or otherwise impossible.
+ */
+ if (do_dtrace || !lx_dtrace_lazyload) {
+ extern void _init(void);
+ _init();
+ }
+
+ if (!dbg_enable)
+ return;
+
+ /*
+ * It's OK to use this value without any locking, as all callers can
+ * use the return value to decide whether extra work should be done
+ * before calling lx_debug().
+ *
+ * If debugging is disabled after a routine calls this function it
+ * doesn't really matter as lx_debug() will see debugging is disabled
+ * and will not output anything.
+ */
+ lx_debug_enabled = 1;
+
+ /* check if there's a debug log file specified */
+ lx_debug_path = dbg_file;
+ if (lx_debug_path == NULL) {
+ /* send all debugging output to /dev/tty */
+ lx_debug_path = "/dev/tty";
+ }
+
+ (void) strlcpy(lx_debug_path_buf, lx_debug_path,
+ sizeof (lx_debug_path_buf));
+ lx_debug_path = lx_debug_path_buf;
+
+ lx_debug("lx_debug: debugging output ENABLED to path: \"%s\"",
+ lx_debug_path);
+}
+
+void
+lx_debug(const char *msg, ...)
+{
+ va_list ap;
+ char *buf;
+ int rv, fd, n;
+ int errno_backup;
+ int size = LX_MSG_MAXLEN + 1;
+
+ if (lx_debug_enabled == 0 && !LX_DEBUG_ENABLED())
+ return;
+
+ /*
+ * If debugging is not enabled, we do not wish to have a large stack
+ * footprint. The buffer allocation is thus done conditionally,
+ * rather than as regular automatic storage.
+ */
+ if ((buf = SAFE_ALLOCA(size)) == NULL)
+ return;
+
+ errno_backup = errno;
+
+ /* prefix the message with pid/tid */
+ if ((n = snprintf(buf, size, "%u/%u: ", getpid(), thr_self())) == -1) {
+ errno = errno_backup;
+ return;
+ }
+
+ /* format the message */
+ va_start(ap, msg);
+ rv = vsnprintf(&buf[n], size - n, msg, ap);
+ va_end(ap);
+ if (rv == -1) {
+ errno = errno_backup;
+ return;
+ }
+
+ /* add a carrige return if there isn't one already */
+ if ((buf[strlen(buf) - 1] != '\n') &&
+ (strlcat(buf, "\n", size) >= size)) {
+ errno = errno_backup;
+ return;
+ }
+
+ LX_DEBUG(buf);
+
+ if (!lx_debug_enabled)
+ return;
+
+ /*
+ * Open the debugging output file. note that we don't protect
+ * ourselves against exec or fork1 here. if an mt process were
+ * to exec/fork1 while we're doing this they'd end up with an
+ * extra open desciptor in their fd space. a'well. shouldn't
+ * really matter.
+ */
+ if ((fd = open(lx_debug_path,
+ O_WRONLY|O_APPEND|O_CREAT|O_NDELAY|O_NOCTTY, 0666)) == -1) {
+ return;
+ }
+ (void) fchmod(fd, 0666);
+
+ /* we retry in case of EINTR */
+ do {
+ rv = write(fd, buf, strlen(buf));
+ } while ((rv == -1) && (errno == EINTR));
+ (void) fsync(fd);
+
+ (void) close(fd);
+ errno = errno_backup;
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/dir.c b/usr/src/lib/brand/lx/lx_brand/common/dir.c
new file mode 100644
index 0000000000..ed10dfb822
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/dir.c
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/dirent.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_syscall.h>
+
+#define LX_NAMEMAX 256
+
+struct lx_old_dirent {
+ long d_ino; /* not l_ino_t */
+ long d_off;
+ ushort_t d_reclen;
+ char d_name[LX_NAMEMAX];
+};
+
+/*
+ * Read in one dirent structure from fd into dirp.
+ * p3 (count) is ignored.
+ */
+/*ARGSUSED*/
+long
+lx_readdir(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ int fd = (int)p1;
+ struct lx_old_dirent *dirp = (struct lx_old_dirent *)p2;
+ uint_t count = sizeof (struct lx_old_dirent);
+ int rc = 0;
+ struct lx_old_dirent _ld;
+ struct dirent *sd = (struct dirent *)&_ld;
+
+ /*
+ * The return value from getdents is not applicable, as
+ * it might have squeezed more than one dirent in the buffer
+ * we provided.
+ *
+ * getdents() will deal with the case of dirp == NULL
+ */
+ if ((rc = getdents(fd, sd, count)) < 0)
+ return (-errno);
+
+ /*
+ * Set rc 1 (pass), or 0 (end of directory).
+ */
+ rc = (sd->d_reclen == 0) ? 0 : 1;
+
+ if (uucopy(sd, dirp, count) != 0)
+ return (-errno);
+
+ return (rc);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/fcntl.c b/usr/src/lib/brand/lx/lx_brand/common/fcntl.c
new file mode 100644
index 0000000000..4796d68855
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/fcntl.c
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/filio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <sys/lx_fcntl.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * flock() applies or removes an advisory lock on the file
+ * associated with the file descriptor fd.
+ *
+ * operation is: LX_LOCK_SH, LX_LOCK_EX, LX_LOCK_UN, LX_LOCK_NB
+ */
+long
+lx_flock(uintptr_t p1, uintptr_t p2)
+{
+ int fd = (int)p1;
+ int operation = (int)p2;
+ struct flock fl;
+ int cmd;
+ int ret;
+
+ if (operation & LX_LOCK_NB) {
+ cmd = F_FLOCK;
+ operation &= ~LX_LOCK_NB; /* turn off this bit */
+ } else {
+ cmd = F_FLOCKW;
+ }
+
+ switch (operation) {
+ case LX_LOCK_UN:
+ fl.l_type = F_UNLCK;
+ break;
+ case LX_LOCK_SH:
+ fl.l_type = F_RDLCK;
+ break;
+ case LX_LOCK_EX:
+ fl.l_type = F_WRLCK;
+ break;
+ default:
+ return (-EINVAL);
+ }
+
+ fl.l_whence = 0;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ fl.l_sysid = 0;
+ fl.l_pid = 0;
+
+ ret = fcntl(fd, cmd, &fl);
+
+ return ((ret == -1) ? -errno : ret);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/file.c b/usr/src/lib/brand/lx/lx_brand/common/file.c
new file mode 100644
index 0000000000..a1f55e2899
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/file.c
@@ -0,0 +1,347 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <fcntl.h>
+#include <string.h>
+#include <utime.h>
+#include <atomic.h>
+#include <sys/syscall.h>
+
+#include <sys/lx_syscall.h>
+#include <sys/lx_types.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_fcntl.h>
+
+#define LX_UTIME_NOW ((1l << 30) - 1l)
+#define LX_UTIME_OMIT ((1l << 30) - 2l)
+
+static int
+install_checkpath(uintptr_t p1)
+{
+ int saved_errno = errno;
+ char path[MAXPATHLEN];
+
+ /*
+ * The "dev" RPM package wants to modify /dev/pts, but /dev/pts is a
+ * lofs mounted copy of /native/dev/pts, so that won't work.
+ *
+ * Instead, if we're trying to modify /dev/pts from install mode, just
+ * act as if it succeded.
+ */
+ if (uucopystr((void *)p1, path, MAXPATHLEN) == -1)
+ return (-errno);
+
+ if (strcmp(path, "/dev/pts") == 0)
+ return (0);
+
+ errno = saved_errno;
+ return (-errno);
+}
+
+/*
+ * Miscellaneous file-related system calls.
+ */
+
+/*
+ * fsync() and fdatasync() - On Illumos, these calls translate into a common
+ * fdsync() syscall with a different parameter. fsync is handled in the
+ * fsync wrapper.
+ */
+long
+lx_fsync(uintptr_t fd)
+{
+ int fildes = (int)fd;
+ struct stat64 statbuf;
+
+ if ((fstat64(fildes, &statbuf) == 0) &&
+ (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode)))
+ return (-EINVAL);
+
+ return (fsync((int)fd) ? -errno : 0);
+}
+
+long
+lx_fdatasync(uintptr_t fd)
+{
+ int fildes = (int)fd;
+ struct stat64 statbuf;
+
+ if ((fstat64(fildes, &statbuf) == 0) &&
+ (S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode)))
+ return (-EINVAL);
+
+ return (fdatasync((int)fd) ? -errno : 0);
+}
+
+long
+lx_utime(uintptr_t p1, uintptr_t p2)
+{
+ int ret;
+
+ ret = utime((const char *)p1, (const struct utimbuf *)p2);
+
+ if (ret < 0) {
+ /*
+ * If utime() failed and we're in install mode, return success
+ * if the the reason we failed was because the source file
+ * didn't actually exist or if we're trying to modify /dev/pts.
+ */
+ if ((lx_install != 0) &&
+ ((errno == ENOENT) || (install_checkpath(p1) == 0)))
+ return (0);
+
+ return (-errno);
+ }
+
+ return (0);
+}
+
+long
+lx_rmdir(uintptr_t p1)
+{
+ int r;
+ char *nm = (char *)p1;
+
+ r = rmdir(nm);
+ if (r < 0) {
+ int terr = errno;
+
+ /*
+ * On both Illumos and Linux rmdir returns EINVAL if the last
+ * component of the path is '.', but on Illumos we also return
+ * this errno if we're trying to remove the CWD. Unfortunately,
+ * at least the LTP test suite assumes that it can rmdir the
+ * CWD, so we need handle this. We try to get out of the
+ * directory we're trying to remove.
+ */
+ if (terr == EINVAL) {
+ int l;
+
+ l = strlen(nm);
+ if (l >= 2 && !(nm[l - 2] == '/' && nm[l - 1] == '.')) {
+ if (chdir("..") == 0 && rmdir(nm) == 0) {
+ return (0);
+ }
+ }
+ }
+
+ return ((terr == EEXIST) ? -ENOTEMPTY : -terr);
+ }
+ return (0);
+}
+
+/*
+ * Exactly the same as Illumos' sysfs(2), except Linux numbers their fs indices
+ * starting at 0, and Illumos starts at 1.
+ */
+long
+lx_sysfs(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ int option = (int)p1;
+ int res;
+
+ /*
+ * Linux actually doesn't have #defines for these; their sysfs(2)
+ * man page literally defines the "option" field as being 1, 2 or 3,
+ * corresponding to Solaris' GETFSIND, GETFSTYP and GETNFSTYP,
+ * respectively.
+ */
+ switch (option) {
+ case 1:
+ if ((res = sysfs(GETFSIND, (const char *)p2)) < 0)
+ return (-errno);
+
+ return (res - 1);
+
+ case 2:
+ if ((res = sysfs(GETFSTYP, (int)p2 + 1,
+ (char *)p3)) < 0)
+ return (-errno);
+
+ return (0);
+
+ case 3:
+ if ((res = sysfs(GETNFSTYP)) < 0)
+ return (-errno);
+
+ return (res);
+
+ default:
+ break;
+ }
+
+ return (-EINVAL);
+}
+
+long
+lx_futimesat(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ int atfd = (int)p1;
+ char *path = (char *)p2;
+ struct timeval *times = (struct timeval *)p3;
+
+ if (atfd == LX_AT_FDCWD)
+ atfd = AT_FDCWD;
+
+ return (futimesat(atfd, path, times) ? -errno : 0);
+}
+
+/*
+ * From the utimensat man page:
+ * On Linux, futimens() is a library function implemented on top of the
+ * utimensat() system call. To support this, the Linux utimensat() system
+ * call implements a nonstandard feature: if pathname is NULL, then the
+ * call modifies the timestamps of the file referred to by the file
+ * descriptor dirfd (which may refer to any type of file). Using this
+ * feature, the call futimens(fd, times) is implemented as:
+ *
+ * utimensat(fd, NULL, times, 0);
+ *
+ * Some of the returns fail here. Linux allows the time to be modified if:
+ *
+ * the caller must have write access to the file
+ * or
+ * the caller's effective user ID must match the owner of the file
+ * or
+ * the caller must have appropriate privileges
+ *
+ * We behave differently. We fail with EPERM if:
+ *
+ * the calling process's euid has write access to the file but does not match
+ * the owner of the file and the calling process does not have the
+ * appropriate privileges
+ *
+ * This causes some of the LTP utimensat tests to fail because they expect an
+ * unprivileged process can update the time on a file it can write but does not
+ * own. There are also other LTP failures when the test uses attributes
+ * (e.g. chattr a+) and expects a failure, but we succeed.
+ */
+long
+lx_utimensat(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ int fd = (int)p1;
+ const char *path = (const char *)p2;
+ const timespec_t *times = (const timespec_t *)p3;
+ timespec_t ts[2];
+ int flag = (int)p4;
+
+ if (times != NULL) {
+ if (uucopy((void *)p3, ts, sizeof (ts)) == -1)
+ return (-errno);
+
+ if (ts[0].tv_nsec == LX_UTIME_NOW)
+ ts[0].tv_nsec = UTIME_NOW;
+ if (ts[1].tv_nsec == LX_UTIME_NOW)
+ ts[1].tv_nsec = UTIME_NOW;
+
+ if (ts[0].tv_nsec == LX_UTIME_OMIT)
+ ts[0].tv_nsec = UTIME_OMIT;
+ if (ts[1].tv_nsec == LX_UTIME_OMIT)
+ ts[1].tv_nsec = UTIME_OMIT;
+
+ times = (const timespec_t *)ts;
+ }
+
+ if (flag == LX_AT_SYMLINK_NOFOLLOW)
+ flag = AT_SYMLINK_NOFOLLOW;
+
+ if (fd == LX_AT_FDCWD)
+ fd = AT_FDCWD;
+
+ if (path == NULL) {
+ return (futimens(fd, times) ? -errno : 0);
+ } else {
+ return (utimensat(fd, path, times, flag) ? -errno : 0);
+ }
+}
+
+/*
+ * Constructs an absolute path string in buf from the path of fd and the
+ * relative path string pointed to by "p1". This is required for emulating
+ * *at() system calls.
+ * Example:
+ * If the path of fd is "/foo/bar" and path is "etc" the string returned is
+ * "/foo/bar/etc", if the fd is a file fd then it fails with ENOTDIR.
+ * If path is absolute then no modifcations are made to it when copied.
+ */
+static int
+getpathat(int fd, uintptr_t p1, char *outbuf, size_t outbuf_size)
+{
+ char pathbuf[MAXPATHLEN];
+ char fdpathbuf[MAXPATHLEN];
+ char *fdpath;
+ struct stat64 statbuf;
+
+ if (uucopystr((void *)p1, pathbuf, MAXPATHLEN) == -1)
+ return (-errno);
+
+ /* If the path is absolute then we can early out */
+ if ((pathbuf[0] == '/') || (fd == LX_AT_FDCWD)) {
+ (void) strlcpy(outbuf, pathbuf, outbuf_size);
+ return (0);
+ }
+
+ fdpath = lx_fd_to_path(fd, fdpathbuf, sizeof (fdpathbuf));
+ if (fdpath == NULL)
+ return (-EBADF);
+
+ if ((fstat64(fd, &statbuf) < 0))
+ return (-EBADF);
+
+ if (!S_ISDIR(statbuf.st_mode))
+ return (-ENOTDIR);
+
+ if (snprintf(outbuf, outbuf_size, "%s/%s", fdpath, pathbuf) >
+ (outbuf_size-1))
+ return (-ENAMETOOLONG);
+
+ return (0);
+}
+
+long
+lx_mknodat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ int atfd = (int)ext1;
+ char pathbuf[MAXPATHLEN];
+ int ret;
+
+ ret = getpathat(atfd, p1, pathbuf, sizeof (pathbuf));
+ if (ret < 0)
+ return (ret);
+
+ return (lx_mknod((uintptr_t)pathbuf, p2, p3));
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/fork.c b/usr/src/lib/brand/lx/lx_brand/common/fork.c
new file mode 100644
index 0000000000..aa14267185
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/fork.c
@@ -0,0 +1,184 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/fork.h>
+#include <sys/syscall.h>
+#include <sys/debug.h>
+#include <strings.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * fork() and vfork()
+ *
+ * These cannot be pass thru system calls because we need libc to do its own
+ * initialization or else bad things will happen (i.e. ending up with a bad
+ * schedctl page). On Linux, there is no such thing as forkall(), so we use
+ * fork1() here.
+ */
+
+long
+lx_fork(void)
+{
+ int ret;
+
+ /*
+ * Inform the in-kernel ptrace(2) subsystem that we are about to
+ * emulate fork(2).
+ */
+ lx_ptrace_clone_begin(LX_PTRACE_O_TRACEFORK, B_FALSE, 0);
+
+ /*
+ * Suspend signal delivery, run the stack management prefork handler
+ * and perform the fork operation.
+ */
+ _sigoff();
+ lx_stack_prefork();
+ ret = fork1();
+ lx_stack_postfork();
+
+ switch (ret) {
+ case -1:
+ _sigon();
+ return (-errno);
+
+ case 0:
+ /*
+ * Returning in the new child. We must free the stacks and
+ * thread-specific data objects for the threads we did not
+ * duplicate; i.e. every other thread.
+ */
+ lx_free_other_stacks();
+
+ lx_ptrace_stop_if_option(LX_PTRACE_O_TRACEFORK, B_TRUE, 0,
+ NULL);
+
+ /*
+ * Re-enable signal delivery in the child and return to the
+ * new process.
+ */
+ _sigon();
+ return (0);
+
+ default:
+ lx_ptrace_stop_if_option(LX_PTRACE_O_TRACEFORK, B_FALSE,
+ (ulong_t)ret, NULL);
+
+ /*
+ * Re-enable signal delivery in the parent and return from
+ * the emulated system call.
+ */
+ _sigon();
+ return (ret);
+ }
+}
+
+long
+lx_vfork(void)
+{
+ int ret;
+ lx_sighandlers_t saved;
+ ucontext_t vforkuc;
+ ucontext_t *ucp;
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ ucp = lx_syscall_regs();
+
+ /*
+ * Inform the in-kernel ptrace(2) subsystem that we are about to
+ * emulate vfork(2).
+ */
+ lx_ptrace_clone_begin(LX_PTRACE_O_TRACEVFORK, B_FALSE, 0);
+
+ /*
+ * Suspend signal delivery, run the stack management prefork handler
+ * and perform the vfork operation. We use the same approach as in
+ * lx_clone for signal handling and child return across vfork. See
+ * the comments in lx_clone for more detail.
+ */
+
+ _sigoff();
+ lx_stack_prefork();
+ lx_sighandlers_save(&saved);
+ lx_tsd->lxtsd_is_vforked++;
+ ret = vfork();
+ if (ret != 0) {
+ /* parent/error */
+ lx_tsd->lxtsd_is_vforked--;
+ lx_sighandlers_restore(&saved);
+ }
+
+ switch (ret) {
+ case -1:
+ lx_stack_postfork();
+ _sigon();
+ return (-errno);
+
+ case 0:
+ /*
+ * child
+ * Unlike the regular fork case where the child also calls
+ * lx_stack_postfork(), we only do that in the parent once it
+ * resumes execution. This is required there to wake any other
+ * threads in that process that are blocked on the lock taken
+ * in lx_stack_prefork().
+ */
+ bcopy(ucp, &vforkuc, sizeof (vforkuc));
+ vforkuc.uc_brand_data[1] = (caddr_t)vforkuc.uc_brand_data[1] -
+ LX_NATIVE_STACK_VFORK_GAP;
+ vforkuc.uc_link = NULL;
+
+ lx_debug("\tvfork native stack sp %p",
+ vforkuc.uc_brand_data[1]);
+
+ /* Stop for ptrace if required. */
+ lx_ptrace_stop_if_option(LX_PTRACE_O_TRACEVFORK, B_TRUE, 0,
+ NULL);
+
+ /*
+ * Return to the child via the specially constructed vfork(2)
+ * context.
+ */
+ LX_EMULATE_RETURN(&vforkuc, LX_SYS_vfork, 0, 0);
+ (void) syscall(SYS_brand, B_EMULATION_DONE, &vforkuc,
+ LX_SYS_vfork, 0, 0);
+
+ VERIFY(0);
+ return (0);
+
+ default:
+ /* parent - child should have exited or exec-ed by now */
+ lx_stack_postfork();
+ lx_ptrace_stop_if_option(LX_PTRACE_O_TRACEVFORK, B_FALSE,
+ (ulong_t)ret, NULL);
+ _sigon();
+ return (ret);
+ }
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
new file mode 100644
index 0000000000..99a0e64f01
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
@@ -0,0 +1,1704 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <sys/inttypes.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/fstyp.h>
+#include <sys/fsid.h>
+#include <sys/systm.h>
+#include <sys/auxv.h>
+#include <sys/frame.h>
+#include <zone.h>
+#include <sys/brand.h>
+#include <sys/epoll.h>
+#include <sys/stack.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <synch.h>
+#include <libelf.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <utime.h>
+#include <dirent.h>
+#include <ucontext.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_brand.h>
+#include <sys/lx_types.h>
+#include <sys/lx_statfs.h>
+#include <sys/lx_signal.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_thread.h>
+#include <lx_auxv.h>
+
+/*
+ * There is a block comment in "uts/common/brand/lx/os/lx_brand.c" that
+ * describes the functioning of the LX brand in some detail.
+ *
+ * *** Setting errno
+ *
+ * This emulation library is loaded onto a seperate link map from the
+ * application whose address space we're running in. The Linux libc errno is
+ * independent of our native libc errno. To pass back an error the emulation
+ * function should return -errno back to the Linux caller.
+ */
+
+char lx_release[LX_KERN_RELEASE_MAX];
+char lx_cmd_name[MAXNAMLEN];
+boolean_t lx_no_abort_handler = B_FALSE;
+
+/*
+ * Map a linux locale ending string to the solaris equivalent.
+ */
+struct lx_locale_ending {
+ const char *linux_end; /* linux ending string */
+ const char *solaris_end; /* to transform with this string */
+ int le_size; /* linux ending string length */
+ int se_size; /* solaris ending string length */
+};
+
+#define l2s_locale(lname, sname) \
+ {(lname), (sname), sizeof ((lname)) - 1, sizeof ((sname)) - 1}
+
+#define MAXLOCALENAMELEN 30
+#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
+#endif
+
+/*
+ * Most syscalls return an int but some return something else, typically a
+ * ssize_t. This can be either an int or a long, depending on if we're compiled
+ * for 32-bit or 64-bit. To correctly propagate the -errno return code in the
+ * 64-bit case, we declare all emulation wrappers will return a long. Thus,
+ * when we save the return value into the %eax or %rax register and return to
+ * Linux, we will have the right size value in both the 32 and 64 bit cases.
+ */
+
+typedef long (*lx_syscall_handler_t)();
+
+static lx_syscall_handler_t lx_handlers[LX_NSYSCALLS + 1];
+
+static uintptr_t stack_size;
+
+#if defined(_LP64)
+long lx_fsb;
+long lx_fs;
+#endif
+int lx_install = 0; /* install mode enabled if non-zero */
+int lx_verbose = 0; /* verbose mode enabled if non-zero */
+int lx_debug_enabled = 0; /* debugging output enabled if non-zero */
+
+pid_t zoneinit_pid; /* zone init PID */
+
+thread_key_t lx_tsd_key;
+
+int
+uucopy_unsafe(const void *src, void *dst, size_t n)
+{
+ bcopy(src, dst, n);
+ return (0);
+}
+
+int
+uucopystr_unsafe(const void *src, void *dst, size_t n)
+{
+ (void) strncpy((char *)src, dst, n);
+ return (0);
+}
+
+static void
+i_lx_msg(int fd, char *msg, va_list ap)
+{
+ int i;
+ char buf[LX_MSG_MAXLEN];
+
+ /* LINTED [possible expansion issues] */
+ i = vsnprintf(buf, sizeof (buf), msg, ap);
+ buf[LX_MSG_MAXLEN - 1] = '\0';
+ if (i == -1)
+ return;
+
+ /* if debugging is enabled, send this message to debug output */
+ if (LX_DEBUG_ISENABLED)
+ lx_debug(buf);
+
+ if (fd == 2) {
+ /*
+ * We let the user choose whether or not to see these
+ * messages on the console.
+ */
+ if (lx_verbose == 0)
+ return;
+ }
+
+ /* we retry in case of EINTR */
+ do {
+ i = write(fd, buf, strlen(buf));
+ } while ((i == -1) && (errno == EINTR));
+}
+
+/*PRINTFLIKE1*/
+void
+lx_err(char *msg, ...)
+{
+ va_list ap;
+
+ assert(msg != NULL);
+
+ va_start(ap, msg);
+ i_lx_msg(STDERR_FILENO, msg, ap);
+ va_end(ap);
+}
+
+/*
+ * This is just a non-zero exit value which also isn't one that would allow
+ * us to easily detect if a branded process exited because of a recursive
+ * fatal error.
+ */
+#define LX_ERR_FATAL 42
+
+/*
+ * Our own custom version of abort(), this routine will be used in place
+ * of the one located in libc. The primary difference is that this version
+ * will first reset the signal handler for SIGABRT to SIG_DFL, ensuring the
+ * SIGABRT sent causes us to dump core and is not caught by a user program.
+ */
+void
+abort(void)
+{
+ static int aborting = 0;
+
+ struct sigaction sa;
+ sigset_t sigmask;
+
+ /* watch out for recursive calls to this function */
+ if (aborting != 0)
+ exit(LX_ERR_FATAL);
+
+ aborting = 1;
+
+ /*
+ * Block all signals here to avoid taking any signals while exiting
+ * in an effort to avoid any strange user interaction with our death.
+ */
+ (void) sigfillset(&sigmask);
+ (void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
+
+ /*
+ * Our own version of abort(3C) that we know will never call
+ * a user-installed SIGABRT handler first. We WANT to die.
+ *
+ * Do this by resetting the handler to SIG_DFL, and releasing any
+ * held SIGABRTs.
+ *
+ * If no SIGABRTs are pending, send ourselves one.
+ *
+ * The while loop is a bit of overkill, but abort(3C) does it to
+ * assure it never returns so we will as well.
+ */
+ (void) sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = SIG_DFL;
+ sa.sa_flags = 0;
+
+ for (;;) {
+ (void) sigaction(SIGABRT, &sa, NULL);
+ (void) sigrelse(SIGABRT);
+ (void) thr_kill(thr_self(), SIGABRT);
+ }
+
+ /*NOTREACHED*/
+}
+
+/*PRINTFLIKE1*/
+void
+lx_msg(char *msg, ...)
+{
+ va_list ap;
+
+ assert(msg != NULL);
+ va_start(ap, msg);
+ i_lx_msg(STDOUT_FILENO, msg, ap);
+ va_end(ap);
+}
+
+/*PRINTFLIKE1*/
+void
+lx_err_fatal(char *msg, ...)
+{
+ va_list ap;
+
+ assert(msg != NULL);
+
+ va_start(ap, msg);
+ i_lx_msg(STDERR_FILENO, msg, ap);
+ va_end(ap);
+ abort();
+}
+
+/*
+ * See if it is safe to alloca() sz bytes. Return 1 for yes, 0 for no.
+ * We can't be certain we won't blow the stack since we don't know where it
+ * starts, but since the stack is only two pages we know any allocation bigger
+ * than that will blow the stack. Fortunately most allocations are small (e.g.
+ * 128 bytes).
+ */
+int
+lx_check_alloca(size_t sz)
+{
+ uintptr_t sp = (uintptr_t)&sz;
+ uintptr_t end = sp - sz;
+
+ return ((end < sp) && (sz < stack_size));
+}
+
+/*PRINTFLIKE1*/
+void
+lx_unsupported(char *msg, ...)
+{
+ va_list ap;
+ char dmsg[256];
+ int lastc;
+
+ assert(msg != NULL);
+
+ /* make a brand call so we can easily dtrace unsupported actions */
+ va_start(ap, msg);
+ (void) vsnprintf(dmsg, sizeof (dmsg), msg, ap);
+ dmsg[255] = '\0';
+ lastc = strlen(dmsg) - 1;
+ if (dmsg[lastc] == '\n')
+ dmsg[lastc] = '\0';
+ (void) syscall(SYS_brand, B_UNSUPPORTED, dmsg);
+ va_end(ap);
+
+ /* send the msg to the error stream */
+ va_start(ap, msg);
+ i_lx_msg(STDERR_FILENO, msg, ap);
+ va_end(ap);
+}
+
+int lx_init(int argc, char *argv[], char *envp[]);
+
+lx_tsd_t *
+lx_get_tsd(void)
+{
+ int ret;
+ lx_tsd_t *lx_tsd;
+
+ if ((ret = thr_getspecific(lx_tsd_key, (void **)&lx_tsd)) != 0) {
+ lx_err_fatal("lx_get_tsd: unable to read "
+ "thread-specific data: %s", strerror(ret));
+ }
+
+ assert(lx_tsd != 0);
+
+ return (lx_tsd);
+}
+
+/*
+ * This function is called from the kernel like a signal handler. Each
+ * function call is a request to provide emulation for a system call that, on
+ * illumos, is implemented in userland. The system call number selection and
+ * argument parsing have already been done by the kernel.
+ */
+void
+lx_emulate(ucontext_t *ucp, int syscall_num, uintptr_t *args)
+{
+ long emu_ret;
+ int emu_errno = 0;
+
+ LX_EMULATE_ENTER(ucp, syscall_num, args);
+ lx_debug("lx_emulate(%p, %d, [%p, %p, %p, %p, %p, %p])\n",
+ ucp, syscall_num, args[0], args[1], args[2], args[3], args[4],
+ args[5]);
+
+ /*
+ * The kernel should have saved us a context that will not restore the
+ * previous signal mask. Some emulated system calls alter the signal
+ * mask; restoring it after the emulation would cancel that out.
+ */
+ assert(!(ucp->uc_flags & UC_SIGMASK));
+
+ /*
+ * The kernel ensures that the syscall_num is sane; Use it as is.
+ */
+ assert(syscall_num >= 0);
+ assert(syscall_num < (sizeof (lx_handlers) / sizeof (lx_handlers[0])));
+ if (lx_handlers[syscall_num] == NULL) {
+ lx_err_fatal("lx_emulate: kernel sent us a call we cannot "
+ "emulate (%d)", syscall_num);
+ }
+
+ /*
+ * Call our handler function:
+ */
+ emu_ret = lx_handlers[syscall_num](args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+
+ /*
+ * If the return value is between -1 and -4095 then it's an errno.
+ * The kernel will translate it to the Linux equivalent for us.
+ */
+ if (emu_ret < 0 && emu_ret > -4096) {
+ emu_errno = (int)-emu_ret;
+ }
+
+ /*
+ * Return to the context we were passed
+ */
+ LX_EMULATE_RETURN(ucp, syscall_num, emu_ret, emu_errno);
+ lx_debug("\tlx_emulate(%d) done (ret %ld / 0x%p ; errno %d)",
+ syscall_num, emu_ret, emu_ret, emu_errno);
+ (void) syscall(SYS_brand, B_EMULATION_DONE, ucp, syscall_num, emu_ret,
+ emu_errno);
+
+ assert(!"cannot be returned here");
+}
+
+static void
+lx_close_fh(FILE *file)
+{
+ int fd, fd_new;
+
+ if (file == NULL)
+ return;
+
+ if ((fd = fileno(file)) < 0)
+ return;
+
+ fd_new = dup(fd);
+ if (fd_new == -1)
+ return;
+
+ (void) fclose(file);
+ (void) dup2(fd_new, fd);
+ (void) close(fd_new);
+}
+
+
+extern int set_l10n_alternate_root(char *path);
+
+/*
+ * Initialize the thread specific data for this thread.
+ */
+void
+lx_init_tsd(lx_tsd_t *lxtsd)
+{
+ int err;
+
+ bzero(lxtsd, sizeof (*lxtsd));
+ lxtsd->lxtsd_exit = LX_ET_NONE;
+
+ /*
+ * The Linux alternate signal stack is initially disabled:
+ */
+ lxtsd->lxtsd_sigaltstack.ss_flags = LX_SS_DISABLE;
+
+ /*
+ * Create a per-thread exit context from the current register and
+ * native/brand stack state. Replace the saved program counter value
+ * with the address of lx_exit_common(); we wish to revector there when
+ * the thread or process is exiting.
+ */
+ if (getcontext(&lxtsd->lxtsd_exit_context) != 0) {
+ lx_err_fatal("Unable to initialize thread-specific exit "
+ "context: %s", strerror(errno));
+ }
+ LX_REG(&lxtsd->lxtsd_exit_context, REG_PC) = (uintptr_t)lx_exit_common;
+
+ /*
+ * Align the stack pointer and clear the frame pointer.
+ */
+ LX_REG(&lxtsd->lxtsd_exit_context, REG_FP) = 0;
+ LX_REG(&lxtsd->lxtsd_exit_context, REG_SP) &= ~(STACK_ALIGN - 1UL);
+#if defined(_LP64)
+#if (STACK_ENTRY_ALIGN != 8) && (STACK_ALIGN != 16)
+#error "lx_init_tsd: unexpected STACK_[ENTRY_]ALIGN values"
+#endif
+ /*
+ * The AMD64 ABI requires that, on entry to a function, the stack
+ * pointer must be 8-byte aligned, but _not_ 16-byte aligned. When
+ * the frame pointer is pushed, the alignment will then be correct.
+ */
+ LX_REG(&lxtsd->lxtsd_exit_context, REG_SP) -= STACK_ENTRY_ALIGN;
+#endif
+
+ /*
+ * Block all signals in the exit context to avoid taking any signals
+ * (to the degree possible) while exiting.
+ */
+ (void) sigfillset(&lxtsd->lxtsd_exit_context.uc_sigmask);
+
+ if ((err = thr_setspecific(lx_tsd_key, lxtsd)) != 0) {
+ lx_err_fatal("Unable to initialize thread-specific data: %s",
+ strerror(err));
+ }
+}
+
+void
+lx_jump_to_linux(ucontext_t *ucp)
+{
+ extern void setcontext_sigmask(ucontext_t *);
+
+ /*
+ * Call into this private libc interface to allow us to use only the
+ * signal mask handling part of a regular setcontext() operation.
+ */
+ setcontext_sigmask(ucp);
+
+ if (syscall(SYS_brand, B_JUMP_TO_LINUX, ucp) != 0) {
+ lx_err_fatal("B_JUMP_TO_LINUX failed: %s", strerror(errno));
+ }
+
+ /*
+ * This system call should not return.
+ */
+ abort();
+}
+
+static void
+lx_start(uintptr_t sp, uintptr_t entry)
+{
+ ucontext_t jump_uc;
+
+ if (getcontext(&jump_uc) != 0) {
+ lx_err_fatal("Unable to getcontext for program start: %s",
+ strerror(errno));
+ }
+
+ /*
+ * We want to load the general registers from this
+ * context, and switch to the BRAND stack.
+ */
+ jump_uc.uc_flags = UC_CPU;
+ jump_uc.uc_brand_data[0] = (void *)LX_UC_STACK_BRAND;
+
+ LX_REG(&jump_uc, REG_FP) = NULL;
+ LX_REG(&jump_uc, REG_SP) = sp;
+ LX_REG(&jump_uc, REG_PC) = entry;
+
+ /*
+ * The AMD64 ABI states that at process entry, %rdx contains "a
+ * function pointer that the application should register with
+ * atexit()". This behavior has been observed in statically linked
+ * i386 programs as well. As a precaution, all of the registers are
+ * zeroed prior to initial execution.
+ */
+#if defined(_LP64)
+ LX_REG(&jump_uc, REG_RAX) = NULL;
+ LX_REG(&jump_uc, REG_RCX) = NULL;
+ LX_REG(&jump_uc, REG_RDX) = NULL;
+ LX_REG(&jump_uc, REG_RBX) = NULL;
+ LX_REG(&jump_uc, REG_RBP) = NULL;
+ LX_REG(&jump_uc, REG_RSI) = NULL;
+ LX_REG(&jump_uc, REG_RDI) = NULL;
+ LX_REG(&jump_uc, REG_R8) = NULL;
+ LX_REG(&jump_uc, REG_R9) = NULL;
+ LX_REG(&jump_uc, REG_R10) = NULL;
+ LX_REG(&jump_uc, REG_R11) = NULL;
+ LX_REG(&jump_uc, REG_R12) = NULL;
+ LX_REG(&jump_uc, REG_R13) = NULL;
+ LX_REG(&jump_uc, REG_R14) = NULL;
+ LX_REG(&jump_uc, REG_R15) = NULL;
+#else
+ LX_REG(&jump_uc, EAX) = NULL;
+ LX_REG(&jump_uc, ECX) = NULL;
+ LX_REG(&jump_uc, EDX) = NULL;
+ LX_REG(&jump_uc, EBX) = NULL;
+ LX_REG(&jump_uc, EBP) = NULL;
+ LX_REG(&jump_uc, ESI) = NULL;
+ LX_REG(&jump_uc, EDI) = NULL;
+#endif /* defined(_LP64) */
+
+ lx_debug("starting Linux program sp %p ldentry %p", sp, entry);
+ lx_jump_to_linux(&jump_uc);
+}
+
+enum lx_env_setting {
+ LXES_INSTALL = 0,
+ LXES_VERBOSE,
+ LXES_DTRACE,
+ LXES_DEBUG,
+ LXES_DEBUG_FILE,
+ LXES_NO_ABORT_HANDLER,
+ LXES_RELEASE,
+ LXES_VERSION,
+ LXES_STRICT,
+ LXES_LIMIT
+};
+
+static void
+lx_parse_env(char *envp[], char *settings[])
+{
+ int i, j;
+ char *env;
+
+ typedef struct lx_env_entry {
+ char *lee_name;
+ int lee_len;
+ int lee_index;
+ } lx_env_entry_t;
+#define LX_ENV_ENTRY(name, idx) { name, (sizeof (name)) - 1, idx }
+ static const lx_env_entry_t lx_env_entries[] = {
+ LX_ENV_ENTRY("LX_INSTALL", LXES_INSTALL),
+ LX_ENV_ENTRY("LX_VERBOSE", LXES_VERBOSE),
+ LX_ENV_ENTRY("LX_DTRACE", LXES_DTRACE),
+ LX_ENV_ENTRY("LX_DEBUG", LXES_DEBUG),
+ LX_ENV_ENTRY("LX_DEBUG_FILE", LXES_DEBUG_FILE),
+ LX_ENV_ENTRY("LX_NO_ABORT_HANDLER", LXES_NO_ABORT_HANDLER),
+ LX_ENV_ENTRY("LX_RELEASE", LXES_RELEASE),
+ LX_ENV_ENTRY("LX_VERSION", LXES_VERSION),
+ LX_ENV_ENTRY("LX_STRICT", LXES_STRICT)
+ };
+#define LX_ENV_ENTRY_COUNT \
+ (sizeof (lx_env_entries) / sizeof (lx_env_entries[0]))
+
+ for (i = 0; (env = envp[i]) != NULL; i++) {
+ if (env[0] != 'L' || env[1] != 'X' || env[2] != '_')
+ continue;
+ for (j = 0; j < LX_ENV_ENTRY_COUNT; j++) {
+ const lx_env_entry_t *lee = &lx_env_entries[j];
+
+ if (strncmp(env, lee->lee_name, lee->lee_len) != 0 ||
+ env[lee->lee_len] != '=')
+ continue;
+ settings[lee->lee_index] = &env[lee->lee_len + 1];
+ break;
+ }
+ }
+}
+
+/*ARGSUSED*/
+int
+lx_init(int argc, char *argv[], char *envp[])
+{
+ auxv_t *ap, *oap;
+ long *p;
+ int err;
+ lx_elf_data_t edp;
+ lx_brand_registration_t reg;
+ lx_tsd_t *lxtsd;
+ char *lx_settings[LXES_LIMIT];
+
+ bzero(&reg, sizeof (reg));
+ stack_size = 2 * sysconf(_SC_PAGESIZE);
+
+ /*
+ * We need to shutdown all libc stdio. libc stdio normally goes to
+ * file descriptors, but since we're actually part of a linux
+ * process we don't own these file descriptors and we can't make
+ * any assumptions about their state.
+ */
+ lx_close_fh(stdin);
+ lx_close_fh(stdout);
+ lx_close_fh(stderr);
+
+ /*
+ * Parse LX-related settings out of the environment array.
+ * This is done manually instead of utilizing libc's getenv() to avoid
+ * triggering any env-cleaning routines which are present.
+ */
+ bzero(lx_settings, sizeof (lx_settings));
+ lx_parse_env(envp, lx_settings);
+
+ /*
+ * Setting LX_NO_ABORT_HANDLER in the environment will prevent the
+ * emulated Linux program from modifying the signal handling
+ * disposition for SIGSEGV or SIGABRT. It is useful for debugging
+ * programs which fall over themselves to prevent useful core files
+ * being generated.
+ */
+ lx_no_abort_handler = (lx_settings[LXES_NO_ABORT_HANDLER] != NULL);
+
+ lx_debug_init(lx_settings[LXES_DTRACE] != NULL,
+ lx_settings[LXES_DEBUG] != NULL,
+ lx_settings[LXES_DEBUG_FILE]);
+
+ if (lx_settings[LXES_RELEASE] == NULL) {
+ if (zone_getattr(getzoneid(), LX_ATTR_KERN_RELEASE,
+ lx_release, sizeof (lx_release)) <= 0)
+ (void) strlcpy(lx_release, "2.4.21",
+ LX_KERN_RELEASE_MAX);
+ } else {
+ (void) strlcpy(lx_release, lx_settings[LXES_RELEASE],
+ LX_KERN_RELEASE_MAX);
+ }
+
+ if (lx_settings[LXES_RELEASE] != NULL ||
+ lx_settings[LXES_VERSION] != NULL) {
+ if (syscall(SYS_brand, B_OVERRIDE_KERN_VER,
+ lx_settings[LXES_RELEASE],
+ lx_settings[LXES_VERSION]) != 0) {
+ lx_debug("failed to override kernel release/version");
+ }
+ }
+ lx_debug("lx_release: %s\n", lx_release);
+
+
+ /*
+ * Should we kill an application that attempts an unimplemented
+ * system call?
+ */
+ if (lx_settings[LXES_STRICT] != NULL) {
+ reg.lxbr_flags |= LX_PROC_STRICT_MODE;
+ lx_debug("STRICT mode enabled.\n");
+ }
+
+ /*
+ * Are we in install mode?
+ */
+ if (lx_settings[LXES_INSTALL] != NULL) {
+ reg.lxbr_flags |= LX_PROC_INSTALL_MODE;
+ lx_install = 1;
+ lx_debug("INSTALL mode enabled.\n");
+ }
+
+ (void) strlcpy(lx_cmd_name, basename(argv[0]), sizeof (lx_cmd_name));
+ lx_debug("executing linux process: %s", argv[0]);
+ lx_debug("branding myself and setting handler to 0x%p",
+ (void *)lx_emulate);
+
+ reg.lxbr_version = LX_VERSION;
+ reg.lxbr_handler = (void *)&lx_emulate;
+
+ /*
+ * Register the address of the user-space handler with the lx brand
+ * module. As a side-effect this leaves the thread in native syscall
+ * mode so that it's ok to continue to make syscalls during setup. We
+ * need to switch to Linux mode at the end of initialization.
+ */
+ if (syscall(SYS_brand, B_REGISTER, &reg))
+ lx_err_fatal("failed to brand the process");
+
+ /* Look up the PID that serves as init for this zone */
+ if ((err = lx_lpid_to_spid(1, &zoneinit_pid)) < 0)
+ lx_err_fatal("Unable to find PID for zone init process: %s",
+ strerror(err));
+
+ /*
+ * Upload data about the lx executable from the kernel.
+ */
+ if (syscall(SYS_brand, B_ELFDATA, (void *)&edp))
+ lx_err_fatal("failed to get required ELF data from the kernel");
+
+ if (lx_statfs_init() != 0)
+ lx_err_fatal("failed to setup the statfs translator");
+
+ /*
+ * Find the aux vector on the stack.
+ */
+ p = (long *)envp;
+ while (*p != NULL)
+ p++;
+
+ /*
+ * Now 'p' points at the NULL word immediately following the environ
+ * pointers. The list of auxv entries _should_ immediately follow.
+ * If anything (such as the native linker or libc) has removed entries
+ * from the environment array, extra NULLs will be present.
+ *
+ * The brand library takes care to avoid such behavior (via the
+ * lx_parse_env routine above) but a belt-and-suspenders approach is
+ * taken for safety.
+ *
+ * The address following the NULL spacer is recorded as the target for
+ * auxv translation and any addition NULLs following it are skipped
+ * until the first auxv entry is located.
+ */
+ p++;
+ oap = (auxv_t *)p;
+ while (*p == NULL)
+ p++;
+ ap = (auxv_t *)p;
+
+ /*
+ * Translate auxv entries to Linux equivalents.
+ */
+ for (; ap->a_type != AT_NULL; ap++) {
+ if (lx_auxv_stol(ap, oap, &edp) == 0) {
+ /*
+ * Copy only auxv entries which Linux programs will
+ * understand. Other entries will be skipped.
+ */
+ oap++;
+ }
+ }
+
+ /* NULL out skipped entries */
+ if (oap < ap) {
+ bzero(oap, (uintptr_t)ap - (uintptr_t)oap);
+ }
+
+ /* Setup signal handler information. */
+ if (lx_siginit()) {
+ lx_err_fatal("failed to initialize lx signals for the "
+ "branded process");
+ }
+
+ /* Setup thread-specific data area for managing linux threads. */
+ if ((err = thr_keycreate(&lx_tsd_key, NULL)) != 0) {
+ lx_err_fatal("thr_keycreate(lx_tsd_key) failed: %s",
+ strerror(err));
+ }
+
+ lx_debug("thr_keycreate created lx_tsd_key (%d)", lx_tsd_key);
+
+ /*
+ * Initialize the thread specific data for this thread.
+ */
+ if ((lxtsd = malloc(sizeof (*lxtsd))) == NULL) {
+ lx_err_fatal("failed to allocate tsd for main thread: %s",
+ strerror(errno));
+ }
+ lx_debug("lx tsd allocated @ %p", lxtsd);
+ lx_init_tsd(lxtsd);
+
+ /*
+ * Allocate the brand emulation stack for the main process thread.
+ * Register the thread-specific data structure with the stack list so
+ * that it may be freed at thread exit or fork(2).
+ */
+ lx_install_stack(NULL, 0, lxtsd);
+
+ /*
+ * The brand linker expects the stack pointer to point to
+ * "argc", which is just before &argv[0].
+ */
+ lx_start((uintptr_t)argv - sizeof (void *), edp.ed_ldentry);
+
+ /*NOTREACHED*/
+ abort();
+ return (0);
+}
+
+/*
+ * We "return" to this function via a context hand-crafted by
+ * "lx_init_tsd()"; see that function for more detail.
+ *
+ * NOTE: Our call frame is on the main thread stack, not the alternate native
+ * stack -- it is safe to release the latter here. The frame does not have a
+ * valid return address, so this function MUST NOT return.
+ */
+void
+lx_exit_common(void)
+{
+ lx_tsd_t *lxtsd = lx_get_tsd();
+ int ev = (0xff & lxtsd->lxtsd_exit_status);
+
+ switch (lxtsd->lxtsd_exit) {
+ case LX_ET_EXIT:
+ lx_debug("lx_exit_common(LX_ET_EXIT, %d, %d)\n", thr_self(),
+ ev);
+
+ if (thr_self() == 1) {
+ /*
+ * Modern versions of glibc will call the exit_group
+ * syscall when exit(3) is called, but if the primary
+ * thread explicitly invokes the exit syscall we now
+ * need to exit with the proper value.
+ */
+ exit(ev);
+ } else {
+ /*
+ * If the thread is exiting, but not the entire process,
+ * we must free the stack we allocated for usermode
+ * emulation. This is safe to do here because the
+ * setcontext() put us back on the BRAND stack for this
+ * process. This function also frees the
+ * thread-specific data object for this thread.
+ */
+ lx_free_stack();
+
+ /*
+ * The native thread return value is never seen so we
+ * pass NULL.
+ */
+ thr_exit(NULL);
+ }
+ break;
+
+ case LX_ET_EXIT_GROUP:
+ lx_debug("lx_exit_common(LX_ET_EXIT_GROUP, %d)\n", ev);
+ exit(ev);
+ break;
+
+ default:
+ abort();
+ }
+
+ abort();
+}
+
+const ucontext_t *
+lx_find_brand_uc(void)
+{
+ ucontext_t *ucp = NULL;
+
+ /*
+ * Ask for the current emulation (or signal handling) ucontext_t...
+ */
+ assert(syscall(SYS_brand, B_GET_CURRENT_CONTEXT, &ucp) == 0);
+
+ for (;;) {
+ uintptr_t flags;
+
+ lx_debug("lx_find_brand_uc: inspect ucp %p...\n", ucp);
+ assert(ucp != NULL);
+
+ flags = (uintptr_t)ucp->uc_brand_data[0];
+
+ if (flags & LX_UC_STACK_BRAND) {
+ lx_debug("lx_find_brand_uc: ucp %p\n", ucp);
+
+ return (ucp);
+ }
+
+ lx_debug("lx_find_brand_uc: skip non-BRAND ucp %p\n", ucp);
+
+ /*
+ * Walk up the context chain to find the most recently stored
+ * brand register state.
+ */
+ ucp = ucp->uc_link;
+ }
+}
+
+uintptr_t
+lx_find_brand_sp(void)
+{
+ const ucontext_t *ucp = lx_find_brand_uc();
+ uintptr_t sp = LX_REG(ucp, REG_SP);
+
+ lx_debug("lx_find_brand_sp: ucp %p sp %p\n", ucp, sp);
+
+ return (sp);
+}
+
+ucontext_t *
+lx_syscall_regs(void)
+{
+ ucontext_t *ucp = NULL;
+ uintptr_t flags;
+
+ /*
+ * Ask for the current emulation (or signal handling) ucontext_t...
+ */
+ assert(syscall(SYS_brand, B_GET_CURRENT_CONTEXT, &ucp) == 0);
+ assert(ucp != NULL);
+
+ /*
+ * Use of the lx_syscall_regs() function implies that the topmost (i.e.
+ * current) context is for a system call emulation request from the
+ * kernel, rather than a signal handling frame.
+ */
+ flags = (uintptr_t)ucp->uc_brand_data[0];
+ assert(flags & LX_UC_FRAME_IS_SYSCALL);
+
+ lx_debug("lx_syscall_regs: ucp %p\n", ucp);
+
+ return (ucp);
+}
+
+int
+lx_lpid_to_spair(pid_t lpid, pid_t *spid, lwpid_t *slwp)
+{
+ pid_t pid;
+ lwpid_t tid;
+
+ if (lpid == 0) {
+ pid = getpid();
+ tid = thr_self();
+ } else {
+ if (syscall(SYS_brand, B_LPID_TO_SPAIR, lpid, &pid, &tid) < 0)
+ return (-errno);
+
+ /*
+ * If the returned pid is -1, that indicates we tried to
+ * look up the PID for init, but that process no longer
+ * exists.
+ */
+ if (pid == -1)
+ return (-ESRCH);
+ }
+
+ if (uucopy(&pid, spid, sizeof (pid_t)) != 0)
+ return (-errno);
+
+ if (uucopy(&tid, slwp, sizeof (lwpid_t)) != 0)
+ return (-errno);
+
+ return (0);
+}
+
+int
+lx_lpid_to_spid(pid_t lpid, pid_t *spid)
+{
+ lwpid_t slwp;
+
+ return (lx_lpid_to_spair(lpid, spid, &slwp));
+}
+
+char *
+lx_fd_to_path(int fd, char *buf, int buf_size)
+{
+ char path_proc[MAXPATHLEN];
+ pid_t pid;
+ int n;
+
+ assert((buf != NULL) && (buf_size >= 0));
+
+ if (fd < 0)
+ return (NULL);
+
+ if ((pid = getpid()) == -1)
+ return (NULL);
+
+ (void) snprintf(path_proc, MAXPATHLEN,
+ "/native/proc/%d/path/%d", pid, fd);
+
+ if ((n = readlink(path_proc, buf, buf_size - 1)) == -1)
+ return (NULL);
+ buf[n] = '\0';
+
+ return (buf);
+}
+
+#if defined(_LP64)
+/* The following is the 64-bit syscall table */
+
+static lx_syscall_handler_t lx_handlers[] = {
+ NULL, /* 0: read */
+ NULL, /* 1: write */
+ NULL, /* 2: open */
+ NULL, /* 3: close */
+ NULL, /* 4: stat */
+ NULL, /* 5: fstat */
+ NULL, /* 6: lstat */
+ NULL, /* 7: poll */
+ NULL, /* 8: lseek */
+ lx_mmap, /* 9: mmap */
+ NULL, /* 10: mprotect */
+ NULL, /* 11: munmap */
+ NULL, /* 12: brk */
+ lx_rt_sigaction, /* 13: rt_sigaction */
+ lx_rt_sigprocmask, /* 14: rt_sigprocmask */
+ lx_rt_sigreturn, /* 15: rt_sigreturn */
+ NULL, /* 16: ioctl */
+ NULL, /* 17: pread64 */
+ NULL, /* 18: pwrite64 */
+ NULL, /* 19: readv */
+ NULL, /* 20: writev */
+ NULL, /* 21: access */
+ NULL, /* 22: pipe */
+ NULL, /* 23: select */
+ NULL, /* 24: sched_yield */
+ lx_remap, /* 25: mremap */
+ NULL, /* 26: msync */
+ NULL, /* 27: mincore */
+ NULL, /* 28: madvise */
+ lx_shmget, /* 29: shmget */
+ lx_shmat, /* 30: shmat */
+ lx_shmctl, /* 31: shmctl */
+ NULL, /* 32: dup */
+ NULL, /* 33: dup2 */
+ NULL, /* 34: pause */
+ NULL, /* 35: nanosleep */
+ NULL, /* 36: getitimer */
+ NULL, /* 37: alarm */
+ lx_setitimer, /* 38: setitimer */
+ NULL, /* 39: getpid */
+ lx_sendfile64, /* 40: sendfile */
+ NULL, /* 41: socket */
+ NULL, /* 42: connect */
+ NULL, /* 43: accept */
+ NULL, /* 44: sendto */
+ NULL, /* 45: recvfrom */
+ NULL, /* 46: sendmsg */
+ NULL, /* 47: recvmsg */
+ NULL, /* 48: shutdown */
+ NULL, /* 49: bind */
+ NULL, /* 50: listen */
+ NULL, /* 51: getsockname */
+ NULL, /* 52: getpeername */
+ NULL, /* 53: socketpair */
+ NULL, /* 54: setsockopt */
+ NULL, /* 55: getsockopt */
+ lx_clone, /* 56: clone */
+ lx_fork, /* 57: fork */
+ lx_vfork, /* 58: vfork */
+ lx_execve, /* 59: execve */
+ lx_exit, /* 60: exit */
+ NULL, /* 61: wait4 */
+ NULL, /* 62: kill */
+ NULL, /* 63: uname */
+ lx_semget, /* 64: semget */
+ lx_semop, /* 65: semop */
+ lx_semctl, /* 66: semctl */
+ lx_shmdt, /* 67: shmdt */
+ lx_msgget, /* 68: msgget */
+ lx_msgsnd, /* 69: msgsnd */
+ lx_msgrcv, /* 70: msgrcv */
+ lx_msgctl, /* 71: msgctl */
+ NULL, /* 72: fcntl */
+ lx_flock, /* 73: flock */
+ lx_fsync, /* 74: fsync */
+ lx_fdatasync, /* 75: fdatasync */
+ lx_truncate, /* 76: truncate */
+ lx_ftruncate, /* 77: ftruncate */
+ NULL, /* 78: getdents */
+ NULL, /* 79: getcwd */
+ NULL, /* 80: chdir */
+ NULL, /* 81: fchdir */
+ NULL, /* 82: rename */
+ NULL, /* 83: mkdir */
+ lx_rmdir, /* 84: rmdir */
+ NULL, /* 85: creat */
+ NULL, /* 86: link */
+ NULL, /* 87: unlink */
+ NULL, /* 88: symlink */
+ NULL, /* 89: readlink */
+ NULL, /* 90: chmod */
+ NULL, /* 91: fchmod */
+ NULL, /* 92: chown */
+ NULL, /* 93: fchown */
+ NULL, /* 94: lchown */
+ NULL, /* 95: umask */
+ NULL, /* 96: gettimeofday */
+ NULL, /* 97: getrlimit */
+ NULL, /* 98: getrusage */
+ NULL, /* 99: sysinfo */
+ lx_times, /* 100: times */
+ NULL, /* 101: ptrace */
+ NULL, /* 102: getuid */
+ NULL, /* 103: syslog */
+ NULL, /* 104: getgid */
+ NULL, /* 105: setuid */
+ NULL, /* 106: setgid */
+ NULL, /* 107: geteuid */
+ NULL, /* 108: getegid */
+ NULL, /* 109: setpgid */
+ NULL, /* 110: getppid */
+ NULL, /* 111: getpgrp */
+ NULL, /* 112: setsid */
+ NULL, /* 113: setreuid */
+ NULL, /* 114: setregid */
+ lx_getgroups, /* 115: getgroups */
+ lx_setgroups, /* 116: setgroups */
+ NULL, /* 117: setresuid */
+ NULL, /* 118: getresuid */
+ NULL, /* 119: setresgid */
+ NULL, /* 120: getresgid */
+ NULL, /* 121: getpgid */
+ NULL, /* 122: setfsuid */
+ NULL, /* 123: setfsgid */
+ NULL, /* 124: getsid */
+ lx_capget, /* 125: capget */
+ lx_capset, /* 126: capset */
+ lx_rt_sigpending, /* 127: rt_sigpending */
+ lx_rt_sigtimedwait, /* 128: rt_sigtimedwait */
+ lx_rt_sigqueueinfo, /* 129: rt_sigqueueinfo */
+ lx_rt_sigsuspend, /* 130: rt_sigsuspend */
+ lx_sigaltstack, /* 131: sigaltstack */
+ lx_utime, /* 132: utime */
+ lx_mknod, /* 133: mknod */
+ NULL, /* 134: uselib */
+ NULL, /* 135: personality */
+ NULL, /* 136: ustat */
+ lx_statfs, /* 137: statfs */
+ lx_fstatfs, /* 138: fstatfs */
+ lx_sysfs, /* 139: sysfs */
+ NULL, /* 140: getpriority */
+ NULL, /* 141: setpriority */
+ NULL, /* 142: sched_setparam */
+ NULL, /* 143: sched_getparam */
+ NULL, /* 144: sched_setscheduler */
+ NULL, /* 145: sched_getscheduler */
+ NULL, /* 146: sched_get_priority_max */
+ NULL, /* 147: sched_get_priority_min */
+ NULL, /* 148: sched_rr_get_interval */
+ NULL, /* 149: mlock */
+ NULL, /* 150: munlock */
+ NULL, /* 151: mlockall */
+ NULL, /* 152: munlockall */
+ NULL, /* 153: vhangup */
+ NULL, /* 154: modify_ldt */
+ NULL, /* 155: pivot_root */
+ lx_sysctl, /* 156: sysctl */
+ NULL, /* 157: prctl */
+ NULL, /* 158: arch_prctl */
+ lx_adjtimex, /* 159: adjtimex */
+ NULL, /* 160: setrlimit */
+ NULL, /* 161: chroot */
+ NULL, /* 162: sync */
+ NULL, /* 163: acct */
+ lx_settimeofday, /* 164: settimeofday */
+ lx_mount, /* 165: mount */
+ NULL, /* 166: umount2 */
+ NULL, /* 167: swapon */
+ NULL, /* 168: swapoff */
+ NULL, /* 169: reboot */
+ NULL, /* 170: sethostname */
+ NULL, /* 171: setdomainname */
+ NULL, /* 172: iopl */
+ NULL, /* 173: ioperm */
+ NULL, /* 174: create_module */
+ NULL, /* 175: init_module */
+ NULL, /* 176: delete_module */
+ NULL, /* 177: get_kernel_syms */
+ lx_query_module, /* 178: query_module */
+ NULL, /* 179: quotactl */
+ NULL, /* 180: nfsservctl */
+ NULL, /* 181: getpmsg */
+ NULL, /* 182: putpmsg */
+ NULL, /* 183: afs_syscall */
+ NULL, /* 184: tux */
+ NULL, /* 185: security */
+ NULL, /* 186: gettid */
+ NULL, /* 187: readahead */
+ NULL, /* 188: setxattr */
+ NULL, /* 189: lsetxattr */
+ NULL, /* 190: fsetxattr */
+ NULL, /* 191: getxattr */
+ NULL, /* 192: lgetxattr */
+ NULL, /* 193: fgetxattr */
+ NULL, /* 194: listxattr */
+ NULL, /* 195: llistxattr */
+ NULL, /* 196: flistxattr */
+ NULL, /* 197: removexattr */
+ NULL, /* 198: lremovexattr */
+ NULL, /* 199: fremovexattr */
+ NULL, /* 200: tkill */
+ NULL, /* 201: time */
+ NULL, /* 202: futex */
+ NULL, /* 203: sched_setaffinity */
+ NULL, /* 204: sched_getaffinity */
+ NULL, /* 205: set_thread_area */
+ NULL, /* 206: io_setup */
+ NULL, /* 207: io_destroy */
+ NULL, /* 208: io_getevents */
+ NULL, /* 209: io_submit */
+ NULL, /* 210: io_cancel */
+ NULL, /* 211: get_thread_area */
+ NULL, /* 212: lookup_dcookie */
+ NULL, /* 213: epoll_create */
+ NULL, /* 214: epoll_ctl_old */
+ NULL, /* 215: epoll_wait_old */
+ NULL, /* 216: remap_file_pages */
+ NULL, /* 217: getdents64 */
+ NULL, /* 218: set_tid_address */
+ NULL, /* 219: restart_syscall */
+ lx_semtimedop, /* 220: semtimedop */
+ NULL, /* 221: fadvise64 */
+ NULL, /* 222: timer_create */
+ lx_timer_settime, /* 223: timer_settime */
+ lx_timer_gettime, /* 224: timer_gettime */
+ lx_timer_getoverrun, /* 225: timer_getoverrun */
+ lx_timer_delete, /* 226: timer_delete */
+ NULL, /* 227: clock_settime */
+ NULL, /* 228: clock_gettime */
+ NULL, /* 229: clock_getres */
+ lx_clock_nanosleep, /* 230: clock_nanosleep */
+ lx_group_exit, /* 231: exit_group */
+ NULL, /* 232: epoll_wait */
+ NULL, /* 233: epoll_ctl */
+ NULL, /* 234: tgkill */
+ lx_utimes, /* 235: utimes */
+ NULL, /* 236: vserver */
+ NULL, /* 237: mbind */
+ NULL, /* 238: set_mempolicy */
+ NULL, /* 239: get_mempolicy */
+ NULL, /* 240: mq_open */
+ NULL, /* 241: mq_unlink */
+ NULL, /* 242: mq_timedsend */
+ NULL, /* 243: mq_timedreceive */
+ NULL, /* 244: mq_notify */
+ NULL, /* 245: mq_getsetattr */
+ NULL, /* 246: kexec_load */
+ NULL, /* 247: waitid */
+ NULL, /* 248: add_key */
+ NULL, /* 249: request_key */
+ NULL, /* 250: keyctl */
+ NULL, /* 251: ioprio_set */
+ NULL, /* 252: ioprio_get */
+ lx_inotify_init, /* 253: inotify_init */
+ lx_inotify_add_watch, /* 254: inotify_add_watch */
+ lx_inotify_rm_watch, /* 255: inotify_rm_watch */
+ NULL, /* 256: migrate_pages */
+ NULL, /* 257: openat */
+ NULL, /* 258: mkdirat */
+ lx_mknodat, /* 259: mknodat */
+ NULL, /* 260: fchownat */
+ lx_futimesat, /* 261: futimesat */
+ NULL, /* 262: fstatat64 */
+ NULL, /* 263: unlinkat */
+ NULL, /* 264: renameat */
+ NULL, /* 265: linkat */
+ NULL, /* 266: symlinkat */
+ NULL, /* 267: readlinkat */
+ NULL, /* 268: fchmodat */
+ NULL, /* 269: faccessat */
+ NULL, /* 270: pselect6 */
+ NULL, /* 271: ppoll */
+ NULL, /* 272: unshare */
+ NULL, /* 273: set_robust_list */
+ NULL, /* 274: get_robust_list */
+ NULL, /* 275: splice */
+ NULL, /* 276: tee */
+ NULL, /* 277: sync_file_range */
+ NULL, /* 278: vmsplice */
+ NULL, /* 279: move_pages */
+ lx_utimensat, /* 280: utimensat */
+ NULL, /* 281: epoll_pwait */
+ lx_signalfd, /* 282: signalfd */
+ lx_timerfd_create, /* 283: timerfd_create */
+ NULL, /* 284: eventfd */
+ NULL, /* 285: fallocate */
+ lx_timerfd_settime, /* 286: timerfd_settime */
+ lx_timerfd_gettime, /* 287: timerfd_gettime */
+ NULL, /* 288: accept4 */
+ lx_signalfd4, /* 289: signalfd4 */
+ NULL, /* 290: eventfd2 */
+ NULL, /* 291: epoll_create1 */
+ NULL, /* 292: dup3 */
+ NULL, /* 293: pipe2 */
+ lx_inotify_init1, /* 294: inotify_init1 */
+ NULL, /* 295: preadv */
+ NULL, /* 296: pwritev */
+ lx_rt_tgsigqueueinfo, /* 297: rt_tgsigqueueinfo */
+ NULL, /* 298: perf_event_open */
+ NULL, /* 299: recvmmsg */
+ NULL, /* 300: fanotify_init */
+ NULL, /* 301: fanotify_mark */
+ NULL, /* 302: prlimit64 */
+ NULL, /* 303: name_to_handle_at */
+ NULL, /* 304: open_by_handle_at */
+ NULL, /* 305: clock_adjtime */
+ NULL, /* 306: syncfs */
+ NULL, /* 307: sendmmsg */
+ NULL, /* 309: setns */
+ NULL, /* 309: getcpu */
+ NULL, /* 310: process_vm_readv */
+ NULL, /* 311: process_vm_writev */
+ NULL, /* 312: kcmp */
+ NULL, /* 313: finit_module */
+ NULL, /* 314: sched_setattr */
+ NULL, /* 315: sched_getattr */
+ NULL, /* 316: renameat2 */
+ NULL, /* 317: seccomp */
+ NULL, /* 318: getrandom */
+ NULL, /* 319: memfd_create */
+ NULL, /* 320: kexec_file_load */
+ NULL, /* 321: bpf */
+ NULL, /* 322: execveat */
+
+ /* XXX TBD gap then x32 syscalls from 512 - 544 */
+};
+
+#else
+/* The following is the 32-bit syscall table */
+
+static lx_syscall_handler_t lx_handlers[] = {
+ NULL, /* 0: nosys */
+ lx_exit, /* 1: exit */
+ lx_fork, /* 2: fork */
+ NULL, /* 3: read */
+ NULL, /* 4: write */
+ NULL, /* 5: open */
+ NULL, /* 6: close */
+ NULL, /* 7: waitpid */
+ NULL, /* 8: creat */
+ NULL, /* 9: link */
+ NULL, /* 10: unlink */
+ lx_execve, /* 11: execve */
+ NULL, /* 12: chdir */
+ NULL, /* 13: time */
+ lx_mknod, /* 14: mknod */
+ NULL, /* 15: chmod */
+ NULL, /* 16: lchown16 */
+ NULL, /* 17: break */
+ NULL, /* 18: stat */
+ NULL, /* 19: lseek */
+ NULL, /* 20: getpid */
+ lx_mount, /* 21: mount */
+ NULL, /* 22: umount */
+ NULL, /* 23: setuid16 */
+ NULL, /* 24: getuid16 */
+ NULL, /* 25: stime */
+ NULL, /* 26: ptrace */
+ NULL, /* 27: alarm */
+ NULL, /* 28: fstat */
+ NULL, /* 29: pause */
+ lx_utime, /* 30: utime */
+ NULL, /* 31: stty */
+ NULL, /* 32: gtty */
+ NULL, /* 33: access */
+ NULL, /* 34: nice */
+ NULL, /* 35: ftime */
+ NULL, /* 36: sync */
+ NULL, /* 37: kill */
+ NULL, /* 38: rename */
+ NULL, /* 39: mkdir */
+ lx_rmdir, /* 40: rmdir */
+ NULL, /* 41: dup */
+ NULL, /* 42: pipe */
+ lx_times, /* 43: times */
+ NULL, /* 44: prof */
+ NULL, /* 45: brk */
+ NULL, /* 46: setgid16 */
+ NULL, /* 47: getgid16 */
+ lx_signal, /* 48: signal */
+ NULL, /* 49: geteuid16 */
+ NULL, /* 50: getegid16 */
+ NULL, /* 51: acct */
+ NULL, /* 52: umount2 */
+ NULL, /* 53: lock */
+ NULL, /* 54: ioctl */
+ NULL, /* 55: fcntl */
+ NULL, /* 56: mpx */
+ NULL, /* 57: setpgid */
+ NULL, /* 58: ulimit */
+ NULL, /* 59: olduname */
+ NULL, /* 60: umask */
+ NULL, /* 61: chroot */
+ NULL, /* 62: ustat */
+ NULL, /* 63: dup2 */
+ NULL, /* 64: getppid */
+ NULL, /* 65: getpgrp */
+ NULL, /* 66: setsid */
+ lx_sigaction, /* 67: sigaction */
+ NULL, /* 68: sgetmask */
+ NULL, /* 69: ssetmask */
+ NULL, /* 70: setreuid16 */
+ NULL, /* 71: setregid16 */
+ lx_sigsuspend, /* 72: sigsuspend */
+ lx_sigpending, /* 73: sigpending */
+ NULL, /* 74: sethostname */
+ NULL, /* 75: setrlimit */
+ NULL, /* 76: getrlimit */
+ NULL, /* 77: getrusage */
+ NULL, /* 78: gettimeofday */
+ lx_settimeofday, /* 79: settimeofday */
+ lx_getgroups16, /* 80: getgroups16 */
+ lx_setgroups16, /* 81: setgroups16 */
+ NULL, /* 82: select */
+ NULL, /* 83: symlink */
+ NULL, /* 84: oldlstat */
+ NULL, /* 85: readlink */
+ NULL, /* 86: uselib */
+ NULL, /* 87: swapon */
+ NULL, /* 88: reboot */
+ lx_readdir, /* 89: readdir */
+ lx_mmap, /* 90: mmap */
+ NULL, /* 91: munmap */
+ lx_truncate, /* 92: truncate */
+ lx_ftruncate, /* 93: ftruncate */
+ NULL, /* 94: fchmod */
+ NULL, /* 95: fchown16 */
+ NULL, /* 96: getpriority */
+ NULL, /* 97: setpriority */
+ NULL, /* 98: profil */
+ lx_statfs, /* 99: statfs */
+ lx_fstatfs, /* 100: fstatfs */
+ NULL, /* 101: ioperm */
+ NULL, /* 102: socketcall */
+ NULL, /* 103: syslog */
+ lx_setitimer, /* 104: setitimer */
+ NULL, /* 105: getitimer */
+ NULL, /* 106: stat */
+ NULL, /* 107: lstat */
+ NULL, /* 108: fstat */
+ NULL, /* 109: uname */
+ NULL, /* 110: oldiopl */
+ NULL, /* 111: vhangup */
+ NULL, /* 112: idle */
+ NULL, /* 113: vm86old */
+ NULL, /* 114: wait4 */
+ NULL, /* 115: swapoff */
+ NULL, /* 116: sysinfo */
+ lx_ipc, /* 117: ipc */
+ lx_fsync, /* 118: fsync */
+ lx_sigreturn, /* 119: sigreturn */
+ lx_clone, /* 120: clone */
+ NULL, /* 121: setdomainname */
+ NULL, /* 122: uname */
+ NULL, /* 123: modify_ldt */
+ lx_adjtimex, /* 124: adjtimex */
+ NULL, /* 125: mprotect */
+ lx_sigprocmask, /* 126: sigprocmask */
+ NULL, /* 127: create_module */
+ NULL, /* 128: init_module */
+ NULL, /* 129: delete_module */
+ NULL, /* 130: get_kernel_syms */
+ NULL, /* 131: quotactl */
+ NULL, /* 132: getpgid */
+ NULL, /* 133: fchdir */
+ NULL, /* 134: bdflush */
+ lx_sysfs, /* 135: sysfs */
+ NULL, /* 136: personality */
+ NULL, /* 137: afs_syscall */
+ NULL, /* 138: setfsuid16 */
+ NULL, /* 139: setfsgid16 */
+ NULL, /* 140: llseek */
+ NULL, /* 141: getdents */
+ NULL, /* 142: select */
+ lx_flock, /* 143: flock */
+ NULL, /* 144: msync */
+ NULL, /* 145: readv */
+ NULL, /* 146: writev */
+ NULL, /* 147: getsid */
+ lx_fdatasync, /* 148: fdatasync */
+ lx_sysctl, /* 149: sysctl */
+ NULL, /* 150: mlock */
+ NULL, /* 151: munlock */
+ NULL, /* 152: mlockall */
+ NULL, /* 153: munlockall */
+ NULL, /* 154: sched_setparam */
+ NULL, /* 155: sched_getparam */
+ NULL, /* 156: sched_setscheduler */
+ NULL, /* 157: sched_getscheduler */
+ NULL, /* 158: sched_yield */
+ NULL, /* 159: sched_get_priority_max */
+ NULL, /* 160: sched_get_priority_min */
+ NULL, /* 161: sched_rr_get_interval */
+ NULL, /* 162: nanosleep */
+ lx_remap, /* 163: mremap */
+ NULL, /* 164: setresuid16 */
+ NULL, /* 165: getresuid16 */
+ NULL, /* 166: vm86 */
+ lx_query_module, /* 167: query_module */
+ NULL, /* 168: poll */
+ NULL, /* 169: nfsservctl */
+ NULL, /* 170: setresgid16 */
+ NULL, /* 171: getresgid16 */
+ NULL, /* 172: prctl */
+ lx_rt_sigreturn, /* 173: rt_sigreturn */
+ lx_rt_sigaction, /* 174: rt_sigaction */
+ lx_rt_sigprocmask, /* 175: rt_sigprocmask */
+ lx_rt_sigpending, /* 176: rt_sigpending */
+ lx_rt_sigtimedwait, /* 177: rt_sigtimedwait */
+ lx_rt_sigqueueinfo, /* 178: rt_sigqueueinfo */
+ lx_rt_sigsuspend, /* 179: rt_sigsuspend */
+ NULL, /* 180: pread64 */
+ NULL, /* 181: pwrite64 */
+ NULL, /* 182: chown16 */
+ NULL, /* 183: getcwd */
+ lx_capget, /* 184: capget */
+ lx_capset, /* 185: capset */
+ lx_sigaltstack, /* 186: sigaltstack */
+ lx_sendfile, /* 187: sendfile */
+ NULL, /* 188: getpmsg */
+ NULL, /* 189: putpmsg */
+ lx_vfork, /* 190: vfork */
+ NULL, /* 191: getrlimit */
+ lx_mmap2, /* 192: mmap2 */
+ lx_truncate64, /* 193: truncate64 */
+ lx_ftruncate64, /* 194: ftruncate64 */
+ NULL, /* 195: stat64 */
+ NULL, /* 196: lstat64 */
+ NULL, /* 197: fstat64 */
+ NULL, /* 198: lchown */
+ NULL, /* 199: getuid */
+ NULL, /* 200: getgid */
+ NULL, /* 201: geteuid */
+ NULL, /* 202: getegid */
+ NULL, /* 203: setreuid */
+ NULL, /* 204: setregid */
+ lx_getgroups, /* 205: getgroups */
+ lx_setgroups, /* 206: setgroups */
+ NULL, /* 207: fchown */
+ NULL, /* 208: setresuid */
+ NULL, /* 209: getresuid */
+ NULL, /* 210: setresgid */
+ NULL, /* 211: getresgid */
+ NULL, /* 212: chown */
+ NULL, /* 213: setuid */
+ NULL, /* 214: setgid */
+ NULL, /* 215: setfsuid */
+ NULL, /* 216: setfsgid */
+ NULL, /* 217: pivot_root */
+ NULL, /* 218: mincore */
+ NULL, /* 219: madvise */
+ NULL, /* 220: getdents64 */
+ NULL, /* 221: fcntl64 */
+ NULL, /* 222: tux */
+ NULL, /* 223: security */
+ NULL, /* 224: gettid */
+ NULL, /* 225: readahead */
+ NULL, /* 226: setxattr */
+ NULL, /* 227: lsetxattr */
+ NULL, /* 228: fsetxattr */
+ NULL, /* 229: getxattr */
+ NULL, /* 230: lgetxattr */
+ NULL, /* 231: fgetxattr */
+ NULL, /* 232: listxattr */
+ NULL, /* 233: llistxattr */
+ NULL, /* 234: flistxattr */
+ NULL, /* 235: removexattr */
+ NULL, /* 236: lremovexattr */
+ NULL, /* 237: fremovexattr */
+ NULL, /* 238: tkill */
+ lx_sendfile64, /* 239: sendfile64 */
+ NULL, /* 240: futex */
+ NULL, /* 241: sched_setaffinity */
+ NULL, /* 242: sched_getaffinity */
+ NULL, /* 243: set_thread_area */
+ NULL, /* 244: get_thread_area */
+ NULL, /* 245: io_setup */
+ NULL, /* 246: io_destroy */
+ NULL, /* 247: io_getevents */
+ NULL, /* 248: io_submit */
+ NULL, /* 249: io_cancel */
+ NULL, /* 250: fadvise64 */
+ NULL, /* 251: nosys */
+ lx_group_exit, /* 252: group_exit */
+ NULL, /* 253: lookup_dcookie */
+ NULL, /* 254: epoll_create */
+ NULL, /* 255: epoll_ctl */
+ NULL, /* 256: epoll_wait */
+ NULL, /* 257: remap_file_pages */
+ NULL, /* 258: set_tid_address */
+ NULL, /* 259: timer_create */
+ lx_timer_settime, /* 260: timer_settime */
+ lx_timer_gettime, /* 261: timer_gettime */
+ lx_timer_getoverrun, /* 262: timer_getoverrun */
+ lx_timer_delete, /* 263: timer_delete */
+ NULL, /* 264: clock_settime */
+ NULL, /* 265: clock_gettime */
+ NULL, /* 266: clock_getres */
+ lx_clock_nanosleep, /* 267: clock_nanosleep */
+ lx_statfs64, /* 268: statfs64 */
+ lx_fstatfs64, /* 269: fstatfs64 */
+ NULL, /* 270: tgkill */
+ lx_utimes, /* 271: utimes */
+ NULL, /* 272: fadvise64_64 */
+ NULL, /* 273: vserver */
+ NULL, /* 274: mbind */
+ NULL, /* 275: get_mempolicy */
+ NULL, /* 276: set_mempolicy */
+ NULL, /* 277: mq_open */
+ NULL, /* 278: mq_unlink */
+ NULL, /* 279: mq_timedsend */
+ NULL, /* 280: mq_timedreceive */
+ NULL, /* 281: mq_notify */
+ NULL, /* 282: mq_getsetattr */
+ NULL, /* 283: kexec_load */
+ NULL, /* 284: waitid */
+ NULL, /* 285: sys_setaltroot */
+ NULL, /* 286: add_key */
+ NULL, /* 287: request_key */
+ NULL, /* 288: keyctl */
+ NULL, /* 289: ioprio_set */
+ NULL, /* 290: ioprio_get */
+ lx_inotify_init, /* 291: inotify_init */
+ lx_inotify_add_watch, /* 292: inotify_add_watch */
+ lx_inotify_rm_watch, /* 293: inotify_rm_watch */
+ NULL, /* 294: migrate_pages */
+ NULL, /* 295: openat */
+ NULL, /* 296: mkdirat */
+ lx_mknodat, /* 297: mknodat */
+ NULL, /* 298: fchownat */
+ lx_futimesat, /* 299: futimesat */
+ NULL, /* 300: fstatat64 */
+ NULL, /* 301: unlinkat */
+ NULL, /* 302: renameat */
+ NULL, /* 303: linkat */
+ NULL, /* 304: symlinkat */
+ NULL, /* 305: readlinkat */
+ NULL, /* 306: fchmodat */
+ NULL, /* 307: faccessat */
+ NULL, /* 308: pselect6 */
+ NULL, /* 309: ppoll */
+ NULL, /* 310: unshare */
+ NULL, /* 311: set_robust_list */
+ NULL, /* 312: get_robust_list */
+ NULL, /* 313: splice */
+ NULL, /* 314: sync_file_range */
+ NULL, /* 315: tee */
+ NULL, /* 316: vmsplice */
+ NULL, /* 317: move_pages */
+ NULL, /* 318: getcpu */
+ NULL, /* 319: epoll_pwait */
+ lx_utimensat, /* 320: utimensat */
+ lx_signalfd, /* 321: signalfd */
+ lx_timerfd_create, /* 322: timerfd_create */
+ NULL, /* 323: eventfd */
+ NULL, /* 324: fallocate */
+ lx_timerfd_settime, /* 325: timerfd_settime */
+ lx_timerfd_gettime, /* 326: timerfd_gettime */
+ lx_signalfd4, /* 327: signalfd4 */
+ NULL, /* 328: eventfd2 */
+ NULL, /* 329: epoll_create1 */
+ NULL, /* 330: dup3 */
+ NULL, /* 331: pipe2 */
+ lx_inotify_init1, /* 332: inotify_init1 */
+ NULL, /* 333: preadv */
+ NULL, /* 334: pwritev */
+ lx_rt_tgsigqueueinfo, /* 335: rt_tgsigqueueinfo */
+ NULL, /* 336: perf_event_open */
+ NULL, /* 337: recvmmsg */
+ NULL, /* 338: fanotify_init */
+ NULL, /* 339: fanotify_mark */
+ NULL, /* 340: prlimit64 */
+ NULL, /* 341: name_to_handle_at */
+ NULL, /* 342: open_by_handle_at */
+ NULL, /* 343: clock_adjtime */
+ NULL, /* 344: syncfs */
+ NULL, /* 345: sendmmsg */
+ NULL, /* 346: setns */
+ NULL, /* 347: process_vm_readv */
+ NULL, /* 348: process_vm_writev */
+ NULL, /* 349: kcmp */
+ NULL, /* 350: finit_module */
+ NULL, /* 351: sched_setattr */
+ NULL, /* 352: sched_getattr */
+ NULL, /* 353: renameat2 */
+ NULL, /* 354: seccomp */
+ NULL, /* 355: getrandom */
+ NULL, /* 356: memfd_create */
+ NULL, /* 357: bpf */
+ NULL, /* 358: execveat */
+};
+#endif
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_provider.d b/usr/src/lib/brand/lx/lx_brand/common/lx_provider.d
new file mode 100644
index 0000000000..14326e8f56
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/lx_provider.d
@@ -0,0 +1,39 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+provider lx {
+ probe debug(char *buf);
+ probe sigdeliver(int sig, void *lx_sigaction, void *lx_sigstack);
+ probe sigreturn(void *lx_ucontext, void *ucontext, uintptr_t sp);
+
+ probe signal__delivery__frame__create(void *lx_sigdeliver_frame);
+ probe signal__delivery__frame__found(void *lx_sigdeliver_frame);
+ probe signal__delivery__frame__corrupt(void *lx_sigdeliver_frame);
+
+ probe signal__post__handler(uintptr_t old_sp, uintptr_t new_sp);
+
+ probe signal__altstack__enable(uintptr_t alt_sp);
+ probe signal__altstack__disable();
+
+ probe emulate__enter(void *ucp, int syscall_num, uintptr_t *args);
+ probe emulate__return(void *ucp, int syscall_num, uintptr_t ret,
+ uintptr_t errn);
+};
+
+#pragma D attributes Evolving/Evolving/ISA provider lx provider
+#pragma D attributes Private/Private/Unknown provider lx module
+#pragma D attributes Private/Private/Unknown provider lx function
+#pragma D attributes Private/Private/ISA provider lx name
+#pragma D attributes Private/Private/ISA provider lx args
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mapfile b/usr/src/lib/brand/lx/lx_brand/common/mapfile
new file mode 100644
index 0000000000..0663f4bc19
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/mapfile
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+#
+# Scope everything local -- our .init section is our only public interface.
+#
+{
+ local:
+ *;
+};
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mapfile-vers b/usr/src/lib/brand/lx/lx_brand/common/mapfile-vers
new file mode 100644
index 0000000000..0663f4bc19
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/mapfile-vers
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+#
+# Scope everything local -- our .init section is our only public interface.
+#
+{
+ local:
+ *;
+};
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mem.c b/usr/src/lib/brand/lx/lx_brand/common/mem.c
new file mode 100644
index 0000000000..9632649091
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/mem.c
@@ -0,0 +1,664 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <procfs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * There are two forms of mmap, mmap() and mmap2(). The only difference is that
+ * the final argument to mmap2() specifies the number of pages, not bytes.
+ * Linux has a number of additional flags, but they are all deprecated. We also
+ * ignore the MAP_GROWSDOWN flag, which has no equivalent on Solaris.
+ *
+ * The Linux mmap() returns ENOMEM in some cases where Solaris returns
+ * EOVERFLOW, so we translate the errno as necessary.
+ */
+
+int pagesize; /* needed for mmap2() */
+
+#define LX_MAP_ANONYMOUS 0x00020
+#define LX_MAP_LOCKED 0x02000
+#define LX_MAP_NORESERVE 0x04000
+#define LX_MAP_32BIT 0x00040
+
+#define TWO_GB 0x80000000
+
+static void lx_remap_anoncache_invalidate(uintptr_t, size_t);
+
+static int
+ltos_mmap_flags(int flags)
+{
+ int new_flags;
+
+ new_flags = flags & (MAP_TYPE | MAP_FIXED);
+
+ if (flags & LX_MAP_ANONYMOUS)
+ new_flags |= MAP_ANONYMOUS;
+ if (flags & LX_MAP_NORESERVE)
+ new_flags |= MAP_NORESERVE;
+
+#if defined(_LP64)
+ if (flags & LX_MAP_32BIT)
+ new_flags |= MAP_32BIT;
+#endif
+
+ return (new_flags);
+}
+
+static void *
+mmap_common(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
+ uintptr_t p5, off64_t p6)
+{
+ void *addr = (void *)p1;
+ size_t len = p2;
+ int prot = p3;
+ int flags = p4;
+ int fd = p5;
+ off64_t off = p6;
+ void *ret;
+
+ if (LX_DEBUG_ISENABLED) {
+ char *path, path_buf[MAXPATHLEN];
+
+ path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
+ if (path == NULL)
+ path = "?";
+
+ lx_debug("\tmmap_common(): fd = %d - %s", fd, path);
+ }
+
+ /*
+ * Under Linux, the file descriptor is ignored when mapping zfod
+ * anonymous memory, On Solaris, we want the fd set to -1 for the
+ * same functionality.
+ */
+ if (flags & LX_MAP_ANONYMOUS)
+ fd = -1;
+
+ /*
+ * We refuse, as a matter of principle, to overcommit memory.
+ * Unfortunately, several bits of important and popular software expect
+ * to be able to pre-allocate large amounts of virtual memory but then
+ * probably never use it. One particularly bad example of this
+ * practice is golang.
+ *
+ * In the interest of running software, unsafe or not, we fudge
+ * something vaguely similar to overcommit by permanently enabling
+ * MAP_NORESERVE unless MAP_LOCKED was requested:
+ */
+ if (!(flags & LX_MAP_LOCKED)) {
+ flags |= LX_MAP_NORESERVE;
+ }
+
+ /*
+ * This is totally insane. The NOTES section in the linux mmap(2) man
+ * page claims that on some architectures, read protection may
+ * automatically include exec protection. It has been observed on a
+ * native linux system that the /proc/<pid>/maps file does indeed
+ * show that segments mmap'd from userland (such as libraries mapped in
+ * by the dynamic linker) all have exec the permission set, even for
+ * data segments.
+ *
+ * This insanity is tempered by the fact that the behavior is disabled
+ * for ELF binaries bearing a PT_GNU_STACK header which lacks PF_X
+ * (which most do). Such a header will clear the READ_IMPLIES_EXEC
+ * flag from the process personality.
+ */
+ if (prot & PROT_READ) {
+ unsigned int personality;
+
+ personality = syscall(SYS_brand, B_GET_PERSONALITY);
+ if ((personality & LX_PER_READ_IMPLIES_EXEC) != 0) {
+ prot |= PROT_EXEC;
+ }
+ }
+
+ ret = mmap64(addr, len, prot, ltos_mmap_flags(flags), fd, off);
+
+ if (ret == MAP_FAILED)
+ return ((void *)(long)(errno == EOVERFLOW ? -ENOMEM : -errno));
+
+ if (flags & LX_MAP_LOCKED)
+ (void) mlock(ret, len);
+
+ /*
+ * We have a new mapping; invalidate any cached anonymous regions that
+ * overlap(ped) with it.
+ */
+ lx_remap_anoncache_invalidate((uintptr_t)ret, len);
+
+ return (ret);
+}
+
+long
+lx_mmap(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
+ uintptr_t p5, uintptr_t p6)
+{
+ return ((ssize_t)mmap_common(p1, p2, p3, p4, p5, (off64_t)p6));
+}
+
+long
+lx_mmap2(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
+ uintptr_t p5, uintptr_t p6)
+{
+ if (pagesize == 0)
+ pagesize = sysconf(_SC_PAGESIZE);
+
+ return ((ssize_t)mmap_common(p1, p2, p3, p4, p5,
+ (off64_t)p6 * pagesize));
+}
+
+
+#define LX_MREMAP_MAYMOVE 1 /* mapping can be moved */
+#define LX_MREMAP_FIXED 2 /* address is fixed */
+
+/*
+ * Unfortunately, the Linux mremap() manpage contains a statement that is, at
+ * best, grossly oversimplified: that mremap() "can be used to implement a
+ * very efficient realloc(3)." To the degree this is true at all, it is only
+ * true narrowly (namely, when large buffers are being expanded but can't be
+ * expanded in place due to virtual address space restrictions) -- but
+ * apparently, someone took this very literally, because variants of glibc
+ * appear to simply implement realloc() in terms of mremap(). This is
+ * unfortunate because absent intelligent usage, it forces realloc() to have
+ * an unncessary interaction with the VM system for small expansions -- and if
+ * realloc() is itself abused (e.g., if a consumer repeatedly expands and
+ * contracts the same memory buffer), the net result can be less efficient
+ * than a much more naive realloc() implementation. And if native Linux is
+ * suboptimal in this case, we are deeply pathological, having not
+ * historically supported mremap() for anonymous mappings at all. To make
+ * this at least palatable, we not only support remap for anonymous mappings
+ * (see lx_remap_anon(), below), we also cache the metadata associated with
+ * these mappings to save both the reads from /proc and the libmapmalloc
+ * alloc/free. We implement the anonymous metadata cache with
+ * lx_remap_anoncache, an LRU cache of prmap_t's that correspond to anonymous
+ * segments that have been resized.
+ */
+#define LX_REMAP_ANONCACHE_NENTRIES 4
+
+static prmap_t lx_remap_anoncache[LX_REMAP_ANONCACHE_NENTRIES];
+static int lx_remap_anoncache_nentries = LX_REMAP_ANONCACHE_NENTRIES;
+static offset_t lx_remap_anoncache_generation;
+static mutex_t lx_remap_anoncache_lock = ERRORCHECKMUTEX;
+
+static void
+lx_remap_anoncache_invalidate(uintptr_t addr, size_t size)
+{
+ int i;
+
+ if (lx_remap_anoncache_generation == 0)
+ return;
+
+ mutex_enter(&lx_remap_anoncache_lock);
+
+ for (i = 0; i < LX_REMAP_ANONCACHE_NENTRIES; i++) {
+ prmap_t *map = &lx_remap_anoncache[i];
+
+ /*
+ * If the ranges overlap at all, we zap it by clearing the
+ * pr_vaddr.
+ */
+ if (addr < map->pr_vaddr + map->pr_size &&
+ map->pr_vaddr < addr + size) {
+ map->pr_vaddr = 0;
+ }
+ }
+
+ mutex_exit(&lx_remap_anoncache_lock);
+}
+
+static void
+lx_remap_anoncache_evict(prmap_t *map)
+{
+ if (map >= &lx_remap_anoncache[0] &&
+ map < &lx_remap_anoncache[LX_REMAP_ANONCACHE_NENTRIES]) {
+ /*
+ * We're already in the cache; we just need to zap our pr_vaddr
+ * to indicate that this has been evicted.
+ */
+ map->pr_vaddr = 0;
+ } else {
+ /*
+ * We need to invalidate this by address and size.
+ */
+ lx_remap_anoncache_invalidate(map->pr_vaddr, map->pr_size);
+ }
+}
+
+static void
+lx_remap_anoncache_load(prmap_t *map, size_t size)
+{
+ offset_t oldest = 0;
+ prmap_t *evict = NULL;
+ int i;
+
+ if (map >= &lx_remap_anoncache[0] &&
+ map < &lx_remap_anoncache[LX_REMAP_ANONCACHE_NENTRIES]) {
+ /*
+ * We're already in the cache -- we just need to update
+ * our LRU field (pr_offset) to reflect the hit.
+ */
+ map->pr_offset = lx_remap_anoncache_generation++;
+ map->pr_size = size;
+ return;
+ }
+
+ mutex_enter(&lx_remap_anoncache_lock);
+
+ for (i = 0; i < lx_remap_anoncache_nentries; i++) {
+ if (lx_remap_anoncache[i].pr_vaddr == 0) {
+ evict = &lx_remap_anoncache[i];
+ break;
+ }
+
+ if (oldest == 0 || lx_remap_anoncache[i].pr_offset < oldest) {
+ oldest = lx_remap_anoncache[i].pr_offset;
+ evict = &lx_remap_anoncache[i];
+ }
+ }
+
+ if (evict != NULL) {
+ *evict = *map;
+ evict->pr_offset = lx_remap_anoncache_generation++;
+ evict->pr_size = size;
+ }
+
+ mutex_exit(&lx_remap_anoncache_lock);
+}
+
+/*
+ * As part of lx_remap() (see below) and to accommodate heavy realloc() use
+ * cases (see the discussion of the lx_remap_anoncache, above), we allow
+ * anonymous segments to be "remapped" in that we are willing to truncate them
+ * or append to them (as much as that's allowed by virtual address space
+ * usage). If we fall out of these cases, we take the more expensive option
+ * of actually copying the data to a new segment -- but we locate the address
+ * in a portion of the address space that should give us plenty of VA space to
+ * expand.
+ */
+static long
+lx_remap_anon(prmap_t *map, prmap_t *maps, int nmap,
+ uintptr_t new_size, uintptr_t flags, uintptr_t new_address)
+{
+ int mflags = MAP_ANON;
+ int prot = 0, i;
+ void *addr, *hint = NULL;
+
+ /*
+ * If our new size is less than our old size and we're either not
+ * being ordered to move it or the address we're being ordered to
+ * move it to is our current address, we can just act as Procrustes
+ * and chop off anything larger than the new size.
+ */
+ if (new_size < map->pr_size && (!(flags & LX_MREMAP_FIXED) ||
+ new_address == map->pr_vaddr)) {
+ if (munmap((void *)(map->pr_vaddr + new_size),
+ map->pr_size - new_size) != 0) {
+ return (-EINVAL);
+ }
+
+ lx_remap_anoncache_load(map, new_size);
+
+ return (map->pr_vaddr);
+ }
+
+ if (map->pr_mflags & (MA_SHM | MA_ISM))
+ return (-EINVAL);
+
+ if (map->pr_mflags & MA_WRITE)
+ prot |= PROT_WRITE;
+
+ if (map->pr_mflags & MA_READ)
+ prot |= PROT_READ;
+
+ if (map->pr_mflags & MA_EXEC)
+ prot |= PROT_EXEC;
+
+ mflags |= (map->pr_mflags & MA_SHARED) ? MAP_SHARED : MAP_PRIVATE;
+
+ if (map->pr_mflags & MA_NORESERVE)
+ mflags |= MAP_NORESERVE;
+
+ /*
+ * If we're not being told where to move it, or the address matches
+ * where we already are, let's try to expand our mapping in place
+ * by adding a fixed mapping after it.
+ */
+ if (!(flags & LX_MREMAP_FIXED) || new_address == map->pr_vaddr) {
+ addr = mmap((void *)(map->pr_vaddr + map->pr_size),
+ new_size - map->pr_size, prot, mflags, -1, 0);
+
+ if (addr == (void *)-1)
+ return (-EINVAL);
+
+ if (addr == (void *)(map->pr_vaddr + map->pr_size)) {
+ lx_remap_anoncache_load(map, new_size);
+ return (map->pr_vaddr);
+ }
+
+ /*
+ * Our advisory address was not followed -- which, as a
+ * practical matter, means that the range conflicted with an
+ * extant mapping. Unmap wherever we landed, and drop into
+ * the relocation case.
+ */
+ (void) munmap(addr, new_size - map->pr_size);
+ }
+
+ lx_remap_anoncache_evict(map);
+
+ /*
+ * If we're here, we actually need to move this mapping -- so if we
+ * can't move it, we're done.
+ */
+ if (!(flags & LX_MREMAP_MAYMOVE))
+ return (-ENOMEM);
+
+ /*
+ * If this is a shared private mapping, we can't remap it.
+ */
+ if (map->pr_mflags & MA_SHARED)
+ return (-EINVAL);
+
+ if (new_address != NULL && (flags & LX_MREMAP_FIXED)) {
+ mflags |= MAP_FIXED;
+ hint = (void *)new_address;
+ } else {
+ /*
+ * We're going to start at the bottom of the address space;
+ * once we hit an address above 2G, we'll treat that as the
+ * bottom of the top of the address space, and set our address
+ * hint below that. To give ourselves plenty of room for
+ * further mremap() expansion, we'll multiply our new size by
+ * 16 and leave that much room between our lowest high address
+ * and our hint.
+ */
+ for (i = 0; i < nmap; i++) {
+ if (maps[i].pr_vaddr < TWO_GB)
+ continue;
+
+ hint = (void *)(maps[i].pr_vaddr - (new_size << 4UL));
+ break;
+ }
+ }
+
+ if ((addr = mmap(hint, new_size, prot, mflags, -1, 0)) == (void *)-1)
+ return (-errno);
+
+ bcopy((void *)map->pr_vaddr, addr, map->pr_size);
+ (void) munmap((void *)map->pr_vaddr, map->pr_size);
+
+ return ((long)addr);
+}
+
+/*
+ * We don't have a native mremap() (and nor do we particularly want one), so
+ * we emulate it strictly in user-land. The idea is simple: we just want to
+ * mmap() the underlying object with the new size and rip down the old mapping.
+ * However, this is problematic because we don't actually have the file
+ * descriptor that corresponds to the resized mapping (and indeed, the mapped
+ * file may not exist in any file system name space). So to get a file
+ * descriptor, we find the (or rather, a) path to the mapped object via its
+ * entry in /proc/self/path and attempt to open it. Assuming that this
+ * succeeds, we then mmap() it and rip down the original mapping. There are
+ * clearly many reasons why this might fail; absent a more apt errno (e.g.,
+ * ENOMEM in some cases), we return EINVAL to denote these cases.
+ */
+long
+lx_remap(uintptr_t old_address, uintptr_t old_size,
+ uintptr_t new_size, uintptr_t flags, uintptr_t new_address)
+{
+ int prot = 0, oflags, mflags = 0, len, fd = -1, i, nmap;
+ prmap_t *map = NULL, *maps;
+ long rval;
+ char path[256], buf[MAXPATHLEN + 1];
+ struct stat st;
+ ssize_t n;
+ static uintptr_t pagesize = 0;
+
+ if (pagesize == 0)
+ pagesize = sysconf(_SC_PAGESIZE);
+
+ if ((flags & (LX_MREMAP_MAYMOVE | LX_MREMAP_FIXED)) == LX_MREMAP_FIXED)
+ return (-EINVAL);
+
+ if (old_address & (pagesize - 1))
+ return (-EINVAL);
+
+ if (new_size == 0)
+ return (-EINVAL);
+
+ if ((flags & LX_MREMAP_FIXED) && (new_address & (pagesize - 1)))
+ return (-EINVAL);
+
+ if (new_size == old_size && !(flags & LX_MREMAP_FIXED))
+ return (old_address);
+
+ /*
+ * First consult the anoncache; if we find the segment there, we'll
+ * drop straight into lx_remap_anon() and save ourself the pain of
+ * the /proc reads.
+ */
+ mutex_enter(&lx_remap_anoncache_lock);
+
+ for (i = 0; i < lx_remap_anoncache_nentries; i++) {
+ map = &lx_remap_anoncache[i];
+
+ if (map->pr_vaddr != old_address)
+ continue;
+
+ if (map->pr_size != old_size)
+ continue;
+
+ if (lx_remap_anon(map, NULL,
+ 0, new_size, 0, new_address) == old_address) {
+ mutex_exit(&lx_remap_anoncache_lock);
+ return (old_address);
+ }
+
+ break;
+ }
+
+ mutex_exit(&lx_remap_anoncache_lock);
+
+ /*
+ * We need to search the mappings to find our specified mapping. Note
+ * that to perform this search, we use /proc/self/rmap instead of
+ * /proc/self/map. This is to accommodate the case where an mmap()'d
+ * and then ftruncate()'d file is being mremap()'d: rmap will report
+ * the size of the mapping (which we need to validate old_size) where
+ * map will report the smaller of the size of the mapping and the
+ * size of the object. (The "r" in "rmap" denotes "reserved".)
+ */
+ if ((fd = open("/native/proc/self/rmap", O_RDONLY)) == -1 ||
+ fstat(fd, &st) != 0) {
+ if (fd >= 0) {
+ (void) close(fd);
+ }
+ return (-EINVAL);
+ }
+
+ /*
+ * Determine the number of mappings we need to read and allocate
+ * a buffer:
+ */
+ nmap = st.st_size / sizeof (prmap_t);
+ if ((maps = malloc((nmap + 1) * sizeof (prmap_t))) == NULL) {
+ (void) close(fd);
+ return (-EINVAL);
+ }
+
+ /*
+ * Read mappings from the kernel and determine how many complete
+ * mappings were read:
+ */
+ if ((n = read(fd, maps, (nmap + 1) * sizeof (prmap_t))) < 0) {
+ lx_debug("\rread of /proc/self/map failed: %s",
+ strerror(errno));
+ (void) close(fd);
+ rval = -EINVAL;
+ goto out;
+ }
+ (void) close(fd);
+
+ nmap = n / sizeof (prmap_t);
+ lx_debug("\tfound %d mappings", nmap);
+
+ /*
+ * Check if any mappings match our arguments:
+ */
+ for (i = 0; i < nmap; i++) {
+ if (maps[i].pr_vaddr == old_address &&
+ maps[i].pr_size == old_size) {
+ map = &maps[i];
+ break;
+ }
+
+ if (maps[i].pr_vaddr <= old_address &&
+ old_address + old_size < maps[i].pr_vaddr +
+ maps[i].pr_size) {
+ /*
+ * We have a mismatch, but our specified range is
+ * a subset of the actual segment; this is EINVAL.
+ */
+ rval = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (i == nmap) {
+ lx_debug("\tno matching mapping found");
+ rval = -EFAULT;
+ goto out;
+ }
+
+ if (map->pr_mflags & (MA_ISM | MA_SHM)) {
+ /*
+ * If this is either ISM or System V shared memory, we're not
+ * going to remap it.
+ */
+ rval = -EINVAL;
+ goto out;
+ }
+
+ oflags = (map->pr_mflags & MA_WRITE) ? O_RDWR : O_RDONLY;
+
+ if (map->pr_mflags & MA_ANON) {
+ /*
+ * This is an anonymous mapping -- which is the one case in
+ * which we perform something that approaches a true remap.
+ */
+ rval = lx_remap_anon(map, maps, nmap,
+ new_size, flags, new_address);
+ goto out;
+ }
+
+ if (!(flags & LX_MREMAP_MAYMOVE)) {
+ /*
+ * If we're not allowed to move this mapping, we're going to
+ * act as if we can't expand it.
+ */
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ if (!(map->pr_mflags & MA_SHARED)) {
+ /*
+ * If this is a private mapping, we're not going to remap it.
+ */
+ rval = -EINVAL;
+ goto out;
+ }
+
+ (void) snprintf(path, sizeof (path),
+ "/native/proc/self/path/%s", map->pr_mapname);
+
+ if ((len = readlink(path, buf, sizeof (buf))) == -1 ||
+ len == sizeof (buf)) {
+ /*
+ * If we failed to read the link, the path might not exist.
+ */
+ rval = -EINVAL;
+ goto out;
+ }
+
+ buf[len] = '\0';
+
+ if ((fd = open(buf, oflags)) == -1) {
+ /*
+ * If we failed to open the object, it may be because it's
+ * not named (i.e., it's anonymous) or because we somehow
+ * don't have permissions. Either way, we're going to kick
+ * it back with EINVAL.
+ */
+ rval = -EINVAL;
+ goto out;
+ }
+
+ if (map->pr_mflags & MA_WRITE)
+ prot |= PROT_WRITE;
+
+ if (map->pr_mflags & MA_READ)
+ prot |= PROT_READ;
+
+ if (map->pr_mflags & MA_EXEC)
+ prot |= PROT_EXEC;
+
+ mflags = MAP_SHARED;
+
+ if (new_address != NULL && (flags & LX_MREMAP_FIXED)) {
+ mflags |= MAP_FIXED;
+ } else {
+ new_address = NULL;
+ }
+
+ rval = (long)mmap((void *)new_address, new_size,
+ prot, mflags, fd, map->pr_offset);
+ (void) close(fd);
+
+ if ((void *)rval == MAP_FAILED) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Our mapping succeeded; we're now going to rip down the old mapping.
+ */
+ (void) munmap((void *)old_address, old_size);
+out:
+ free(maps);
+ return (rval);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/misc.c b/usr/src/lib/brand/lx/lx_brand/common/misc.c
new file mode 100644
index 0000000000..a223d0ac35
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/misc.c
@@ -0,0 +1,359 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <priv.h>
+#include <strings.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysmacros.h>
+#include <sys/systeminfo.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/inotify.h>
+#include <sys/eventfd.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_fcntl.h>
+
+/*
+ * {get,set}groups16() - Handle the conversion between 16-bit Linux gids and
+ * 32-bit illumos gids.
+ */
+long
+lx_getgroups16(uintptr_t p1, uintptr_t p2)
+{
+ int count = (int)p1;
+ lx_gid16_t *grouplist = (lx_gid16_t *)p2;
+ gid_t *grouplist32;
+ int ret;
+ int i;
+
+ if (count < 0)
+ return (-EINVAL);
+
+ grouplist32 = malloc(count * sizeof (gid_t));
+ if (grouplist32 == NULL && count > 0) {
+ free(grouplist32);
+ return (-ENOMEM);
+ }
+ if ((ret = getgroups(count, grouplist32)) < 0) {
+ free(grouplist32);
+ return (-errno);
+ }
+
+ /* we must not modify the list if the incoming count was 0 */
+ if (count > 0) {
+ for (i = 0; i < ret; i++)
+ grouplist[i] = LX_GID32_TO_GID16(grouplist32[i]);
+ }
+
+ free(grouplist32);
+ return (ret);
+}
+
+long
+lx_setgroups16(uintptr_t p1, uintptr_t p2)
+{
+ long rv;
+ int count = (int)p1;
+ lx_gid16_t *grouplist = NULL;
+ gid_t *grouplist32 = NULL;
+ int i;
+
+ if ((grouplist = malloc(count * sizeof (lx_gid16_t))) == NULL) {
+ return (-ENOMEM);
+ }
+ if (uucopy((void *)p2, grouplist, count * sizeof (lx_gid16_t)) != 0) {
+ free(grouplist);
+ return (-EFAULT);
+ }
+
+ grouplist32 = malloc(count * sizeof (gid_t));
+ if (grouplist32 == NULL) {
+ free(grouplist);
+ return (-ENOMEM);
+ }
+ for (i = 0; i < count; i++)
+ grouplist32[i] = LX_GID16_TO_GID32(grouplist[i]);
+
+ /* order matters here to get the correct errno back */
+ if (count > NGROUPS_MAX_DEFAULT) {
+ free(grouplist);
+ free(grouplist32);
+ return (-EINVAL);
+ }
+
+ rv = setgroups(count, grouplist32);
+
+ free(grouplist);
+ free(grouplist32);
+
+ return (rv != 0 ? -errno : 0);
+}
+
+/*
+ * mknod() - Since we don't have the SYS_CONFIG privilege within a zone, the
+ * only mode we have to support is S_IFIFO. We also have to distinguish between
+ * an invalid type and insufficient privileges.
+ */
+#define LX_S_IFMT 0170000
+#define LX_S_IFDIR 0040000
+#define LX_S_IFCHR 0020000
+#define LX_S_IFBLK 0060000
+#define LX_S_IFREG 0100000
+#define LX_S_IFIFO 0010000
+#define LX_S_IFLNK 0120000
+#define LX_S_IFSOCK 0140000
+
+/*ARGSUSED*/
+long
+lx_mknod(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ char *path = (char *)p1;
+ lx_dev_t lx_dev = (lx_dev_t)p3;
+ struct sockaddr_un sockaddr;
+ struct stat statbuf;
+ mode_t mode, type;
+ dev_t dev;
+ int fd;
+
+ type = ((mode_t)p2 & LX_S_IFMT);
+ mode = ((mode_t)p2 & 07777);
+
+ switch (type) {
+ case 0:
+ case LX_S_IFREG:
+ /* create a regular file */
+ if (stat(path, &statbuf) == 0)
+ return (-EEXIST);
+
+ if (errno != ENOENT)
+ return (-errno);
+
+ if ((fd = creat(path, mode)) < 0)
+ return (-errno);
+
+ (void) close(fd);
+ return (0);
+
+ case LX_S_IFSOCK:
+ /*
+ * Create a UNIX domain socket.
+ *
+ * Most programmers aren't even aware you can do this.
+ *
+ * Note you can also do this via illumos' mknod(2), but
+ * Linux allows anyone who can create a UNIX domain
+ * socket via bind(2) to create one via mknod(2);
+ * illumos requires the caller to be privileged.
+ */
+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return (-errno);
+
+ if (stat(path, &statbuf) == 0)
+ return (-EEXIST);
+
+ if (errno != ENOENT)
+ return (-errno);
+
+ if (uucopy(path, &sockaddr.sun_path,
+ sizeof (sockaddr.sun_path)) < 0)
+ return (-errno);
+
+ /* assure NULL termination of sockaddr.sun_path */
+ sockaddr.sun_path[sizeof (sockaddr.sun_path) - 1] = '\0';
+ sockaddr.sun_family = AF_UNIX;
+
+ if (bind(fd, (struct sockaddr *)&sockaddr,
+ strlen(sockaddr.sun_path) +
+ sizeof (sockaddr.sun_family)) < 0)
+ return (-errno);
+
+ (void) close(fd);
+ return (0);
+
+ case LX_S_IFIFO:
+ dev = 0;
+ break;
+
+ case LX_S_IFCHR:
+ case LX_S_IFBLK:
+ /*
+ * The "dev" RPM package wants to create all possible Linux
+ * device nodes, so just report its mknod()s as having
+ * succeeded if we're in install mode.
+ */
+ if (lx_install != 0) {
+ lx_debug("lx_mknod: install mode spoofed creation of "
+ "Linux device [%lld, %lld]\n",
+ LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev));
+
+ return (0);
+ }
+
+ dev = makedevice(LX_GETMAJOR(lx_dev), LX_GETMINOR(lx_dev));
+ break;
+
+ default:
+ return (-EINVAL);
+ }
+
+ return (mknod(path, mode | type, dev) ? -errno : 0);
+}
+
+long
+lx_execve(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ char *filename = (char *)p1;
+ char **argv = (char **)p2;
+ char **envp = (char **)p3;
+ char *nullist[] = { NULL };
+
+ if (argv == NULL)
+ argv = nullist;
+
+ /*
+ * Emulate PR_SET_KEEPCAPS which is reset on execve. If this is not done
+ * the emulated capabilities could be reduced more than expected.
+ */
+ (void) setpflags(PRIV_AWARE_RESET, 1);
+
+ /* This is a normal exec call. */
+ (void) execve(filename, argv, envp);
+
+ return (-errno);
+}
+
+long
+lx_setgroups(uintptr_t p1, uintptr_t p2)
+{
+ int ng = (int)p1;
+ gid_t *glist = NULL;
+ int i, r;
+
+ lx_debug("\tlx_setgroups(%d, 0x%p", ng, p2);
+
+ if (ng > 0) {
+ if ((glist = (gid_t *)malloc(ng * sizeof (gid_t))) == NULL)
+ return (-ENOMEM);
+
+ if (uucopy((void *)p2, glist, ng * sizeof (gid_t)) != 0) {
+ free(glist);
+ return (-errno);
+ }
+
+ /*
+ * Linux doesn't check the validity of the group IDs, but
+ * illumos does. Change any invalid group IDs to a known, valid
+ * value (yuck).
+ */
+ for (i = 0; i < ng; i++) {
+ if (glist[i] > MAXUID)
+ glist[i] = MAXUID;
+ }
+ }
+
+ /* order matters here to get the correct errno back */
+ if (ng > NGROUPS_MAX_DEFAULT) {
+ free(glist);
+ return (-EINVAL);
+ }
+
+ r = syscall(SYS_brand, B_HELPER_SETGROUPS, ng, glist);
+
+ free(glist);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_getgroups(int gidsetsize, gid_t *grouplist)
+{
+ int r;
+
+ r = getgroups(gidsetsize, grouplist);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_inotify_add_watch(int fd, const char *pathname, uint32_t mask)
+{
+ int r;
+
+ r = inotify_add_watch(fd, pathname, mask);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_inotify_init(void)
+{
+ int r;
+
+ r = inotify_init();
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_inotify_init1(int flags)
+{
+ int r;
+
+ r = inotify_init1(flags);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_inotify_rm_watch(int fd, int wd)
+{
+ int r;
+
+ r = inotify_rm_watch(fd, wd);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_shmdt(char *shmaddr)
+{
+ int r;
+
+ r = shmdt(shmaddr);
+ return ((r == -1) ? -errno : r);
+}
+
+long
+lx_utimes(const char *path, const struct timeval times[2])
+{
+ int r;
+
+ r = utimes(path, times);
+ return ((r == -1) ? -errno : r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/module.c b/usr/src/lib/brand/lx/lx_brand/common/module.c
new file mode 100644
index 0000000000..78a593712f
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/module.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * We don't support Linux modules, but we have to emulate enough of the system
+ * calls to show that we don't have any modules installed.
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * For query_module(), we provide an empty list of modules, and return ENOENT
+ * on any request for a specific module.
+ */
+#define LX_QM_MODULES 1
+#define LX_QM_DEPS 2
+#define LX_QM_REFS 3
+#define LX_QM_SYMBOLS 4
+#define LX_QM_INFO 5
+
+/*ARGSUSED*/
+long
+lx_query_module(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
+ uintptr_t p5)
+{
+ /*
+ * parameter p1 is the 'name' argument.
+ */
+ int which = (int)p2;
+ char *buf = (char *)p3;
+ size_t bufsize = (size_t)p4;
+ size_t *ret = (size_t *)p5;
+
+ switch (which) {
+ case 0:
+ /*
+ * Special case: always return 0
+ */
+ return (0);
+
+ case LX_QM_MODULES:
+ /*
+ * Generate an empty list of modules.
+ */
+ if (bufsize && buf)
+ buf[0] = '\0';
+ if (ret)
+ *ret = 0;
+ return (0);
+
+ case LX_QM_DEPS:
+ case LX_QM_REFS:
+ case LX_QM_SYMBOLS:
+ case LX_QM_INFO:
+ /*
+ * Any requests for specific module information return ENOENT.
+ */
+ return (-ENOENT);
+
+ default:
+ return (-EINVAL);
+ }
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mount.c b/usr/src/lib/brand/lx/lx_brand/common/mount.c
new file mode 100644
index 0000000000..6ecd5cfc4f
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/mount.c
@@ -0,0 +1,540 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <strings.h>
+#include <nfs/mount.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_mount.h>
+
+/*
+ * support definitions
+ */
+union fh_buffer {
+ struct nfs_fid fh2;
+ struct nfs_fh3 fh3;
+ char fh_data[NFS3_FHSIZE + 2];
+};
+
+static int
+i_add_option(char *option, char *buf, size_t buf_size)
+{
+ char *fmt_str = NULL;
+
+ assert((option != NULL) && (strlen(option) > 0));
+ assert((buf != NULL) && (buf_size > 0));
+
+ if (buf[0] == '\0') {
+ fmt_str = "%s";
+ } else {
+ fmt_str = ",%s";
+ }
+
+ buf_size -= strlen(buf);
+ buf += strlen(buf);
+
+ /*LINTED*/
+ if (snprintf(buf, buf_size, fmt_str, option) > (buf_size - 1))
+ return (-EOVERFLOW);
+ return (0);
+}
+
+static int
+i_add_option_int(char *option, int val, char *buf, size_t buf_size)
+{
+ char *fmt_str = NULL;
+
+ assert((option != NULL) && (strlen(option) > 0));
+ assert((buf != NULL) && (buf_size > 0));
+
+ if (buf[0] == '\0') {
+ fmt_str = "%s=%d";
+ } else {
+ fmt_str = ",%s=%d";
+ }
+
+ buf_size -= strlen(buf);
+ buf += strlen(buf);
+
+ /*LINTED*/
+ if (snprintf(buf, buf_size, fmt_str, option, val) > (buf_size - 1))
+ return (-EOVERFLOW);
+ return (0);
+}
+
+static int
+i_make_nfs_args(lx_nfs_mount_data_t *lx_nmd, struct nfs_args *nfs_args,
+ struct netbuf *nfs_args_addr, struct knetconfig *nfs_args_knconf,
+ union fh_buffer *nfs_args_fh, struct sec_data *nfs_args_secdata,
+ char *fstype, char *options, int options_size)
+{
+ struct stat statbuf;
+ int i, rv, use_tcp;
+
+ /* Sanity check the incomming Linux request. */
+ if ((lx_nmd->nmd_rsize < 0) || (lx_nmd->nmd_wsize < 0) ||
+ (lx_nmd->nmd_timeo < 0) || (lx_nmd->nmd_retrans < 0) ||
+ (lx_nmd->nmd_acregmin < 0) || (lx_nmd->nmd_acregmax < 0) ||
+ (lx_nmd->nmd_acdirmax < 0)) {
+ return (-EINVAL);
+ }
+
+ /*
+ * Additional sanity checks of incomming request.
+ *
+ * Some of the sanity checks below should probably return
+ * EINVAL (or some other error code) instead or ENOTSUP,
+ * but without experiminting on Linux to see how it
+ * deals with certain strange values there is no way
+ * to really know what we should return, hence we return
+ * ENOTSUP to tell us that eventually if we see some
+ * application hitting the problem we can go to a real
+ * Linux system, figure out how it deals with the situation
+ * and update our code to handle it in the same fashion.
+ */
+ if (lx_nmd->nmd_version != 4) {
+ lx_unsupported("unsupported nfs mount request, "
+ "unrecognized NFS mount structure: %d\n",
+ lx_nmd->nmd_version);
+ return (-ENOTSUP);
+ }
+ if ((lx_nmd->nmd_flags & ~LX_NFS_MOUNT_SUPPORTED) != 0) {
+ lx_unsupported("unsupported nfs mount request, "
+ "flags: 0x%x\n", lx_nmd->nmd_flags);
+ return (-ENOTSUP);
+ }
+ if (lx_nmd->nmd_addr.sin_family != AF_INET) {
+ lx_unsupported("unsupported nfs mount request, "
+ "transport address family: 0x%x\n",
+ lx_nmd->nmd_addr.sin_family);
+ return (-ENOTSUP);
+ }
+ for (i = 0; i < LX_NMD_MAXHOSTNAMELEN; i++) {
+ if (lx_nmd->nmd_hostname[i] == '\0')
+ break;
+ }
+ if (i == 0) {
+ lx_unsupported("unsupported nfs mount request, "
+ "no hostname specified\n");
+ return (-ENOTSUP);
+ }
+ if (i == LX_NMD_MAXHOSTNAMELEN) {
+ lx_unsupported("unsupported nfs mount request, "
+ "hostname not terminated\n");
+ return (-ENOTSUP);
+ }
+ if (lx_nmd->nmd_namlen < i) {
+ lx_unsupported("unsupported nfs mount request, "
+ "invalid namlen value: 0x%x\n", lx_nmd->nmd_namlen);
+ return (-ENOTSUP);
+ }
+ if (lx_nmd->nmd_bsize != 0) {
+ lx_unsupported("unsupported nfs mount request, "
+ "bsize value: 0x%x\n", lx_nmd->nmd_bsize);
+ return (-ENOTSUP);
+ }
+
+ /* Initialize and clear the output structure pointers passed in. */
+ bzero(nfs_args, sizeof (*nfs_args));
+ bzero(nfs_args_addr, sizeof (*nfs_args_addr));
+ bzero(nfs_args_knconf, sizeof (*nfs_args_knconf));
+ bzero(nfs_args_fh, sizeof (*nfs_args_fh));
+ bzero(nfs_args_secdata, sizeof (*nfs_args_secdata));
+ nfs_args->addr = nfs_args_addr;
+ nfs_args->knconf = nfs_args_knconf;
+ nfs_args->fh = (caddr_t)nfs_args_fh;
+ nfs_args->nfs_ext_u.nfs_extB.secdata = nfs_args_secdata;
+
+ /* Check if we're using tcp. */
+ use_tcp = (lx_nmd->nmd_flags & LX_NFS_MOUNT_TCP) ? 1 : 0;
+
+ /*
+ * These seem to be the default flags used by Solaris for v2 and v3
+ * nfs mounts.
+ *
+ * Don't bother with NFSMNT_TRYRDMA since we always specify a
+ * transport (either udp or tcp).
+ */
+ nfs_args->flags = NFSMNT_NEWARGS | NFSMNT_KNCONF | NFSMNT_INT |
+ NFSMNT_HOSTNAME;
+
+ /* Translate some Linux mount flags into Solaris mount flags. */
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_SOFT)
+ nfs_args->flags |= NFSMNT_SOFT;
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_INTR)
+ nfs_args->flags |= NFSMNT_INT;
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_POSIX)
+ nfs_args->flags |= NFSMNT_POSIX;
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NOCTO)
+ nfs_args->flags |= NFSMNT_NOCTO;
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NOAC)
+ nfs_args->flags |= NFSMNT_NOAC;
+ if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NONLM)
+ nfs_args->flags |= NFSMNT_LLOCK;
+
+ if ((lx_nmd->nmd_flags & LX_NFS_MOUNT_VER3) != 0) {
+ (void) strcpy(fstype, "nfs3");
+ if ((rv = i_add_option_int("vers", 3,
+ options, options_size)) != 0)
+ return (rv);
+
+ if (lx_nmd->nmd_root.lx_fh3_length >
+ sizeof (nfs_args_fh->fh3.fh3_u.data)) {
+ lx_unsupported("unsupported nfs mount request, "
+ "nfs file handle length: 0x%x\n",
+ lx_nmd->nmd_root.lx_fh3_length);
+ return (-ENOTSUP);
+ }
+
+ /* Set the v3 file handle info. */
+ nfs_args_fh->fh3.fh3_length = lx_nmd->nmd_root.lx_fh3_length;
+ bcopy(&lx_nmd->nmd_root.lx_fh3_data,
+ nfs_args_fh->fh3.fh3_u.data,
+ lx_nmd->nmd_root.lx_fh3_length);
+ } else {
+ /*
+ * Assume nfs v2. Note that this could also be a v1
+ * mount request but there doesn't seem to be any difference
+ * in the parameters passed to the Linux mount system
+ * call for v1 or v2 mounts so there is no way of really
+ * knowing.
+ */
+ (void) strcpy(fstype, "nfs");
+ if ((rv = i_add_option_int("vers", 2,
+ options, options_size)) != 0)
+ return (rv);
+
+ /* Solaris seems to add this flag when using v2. */
+ nfs_args->flags |= NFSMNT_SECDEFAULT;
+
+ /* Set the v2 file handle info. */
+ bcopy(&lx_nmd->nmd_old_root,
+ nfs_args_fh, sizeof (nfs_args_fh->fh2));
+ }
+
+ /*
+ * We can't use getnetconfig() here because there is no netconfig
+ * database in linux.
+ */
+ nfs_args_knconf->knc_protofmly = "inet";
+ if (use_tcp) {
+ /*
+ * TCP uses NC_TPI_COTS_ORD semantics.
+ * See /etc/netconfig.
+ */
+ nfs_args_knconf->knc_semantics = NC_TPI_COTS_ORD;
+ nfs_args_knconf->knc_proto = "tcp";
+ if ((rv = i_add_option("proto=tcp",
+ options, options_size)) != 0)
+ return (rv);
+ if (stat("/dev/tcp", &statbuf) != 0)
+ return (-errno);
+ nfs_args_knconf->knc_rdev = statbuf.st_rdev;
+ } else {
+ /*
+ * Assume UDP. UDP uses NC_TPI_CLTS semantics.
+ * See /etc/netconfig.
+ */
+ nfs_args_knconf->knc_semantics = NC_TPI_CLTS;
+ nfs_args_knconf->knc_proto = "udp";
+ if ((rv = i_add_option("proto=udp",
+ options, options_size)) != 0)
+ return (rv);
+ if (stat("/dev/udp", &statbuf) != 0)
+ return (-errno);
+ nfs_args_knconf->knc_rdev = statbuf.st_rdev;
+ }
+
+ /* Set the server address. */
+ nfs_args_addr->maxlen = nfs_args_addr->len =
+ sizeof (struct sockaddr_in);
+ nfs_args_addr->buf = (char *)&lx_nmd->nmd_addr;
+
+ /* Set the server hostname string. */
+ nfs_args->hostname = lx_nmd->nmd_hostname;
+
+ /* Translate Linux nfs mount parameters into Solaris mount options. */
+ if (lx_nmd->nmd_rsize != LX_NMD_DEFAULT_RSIZE) {
+ if ((rv = i_add_option_int("rsize", lx_nmd->nmd_rsize,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->rsize = lx_nmd->nmd_rsize;
+ nfs_args->flags |= NFSMNT_RSIZE;
+ }
+ if (lx_nmd->nmd_wsize != LX_NMD_DEFAULT_WSIZE) {
+ if ((rv = i_add_option_int("wsize", lx_nmd->nmd_wsize,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->wsize = lx_nmd->nmd_wsize;
+ nfs_args->flags |= NFSMNT_WSIZE;
+ }
+ if ((rv = i_add_option_int("timeo", lx_nmd->nmd_timeo,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->timeo = lx_nmd->nmd_timeo;
+ nfs_args->flags |= NFSMNT_TIMEO;
+ if ((rv = i_add_option_int("retrans", lx_nmd->nmd_retrans,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->retrans = lx_nmd->nmd_retrans;
+ nfs_args->flags |= NFSMNT_RETRANS;
+ if ((rv = i_add_option_int("acregmin", lx_nmd->nmd_acregmin,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->acregmin = lx_nmd->nmd_acregmin;
+ nfs_args->flags |= NFSMNT_ACREGMIN;
+ if ((rv = i_add_option_int("acregmax", lx_nmd->nmd_acregmax,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->acregmax = lx_nmd->nmd_acregmax;
+ nfs_args->flags |= NFSMNT_ACREGMAX;
+ if ((rv = i_add_option_int("acdirmin", lx_nmd->nmd_acdirmin,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->acdirmin = lx_nmd->nmd_acdirmin;
+ nfs_args->flags |= NFSMNT_ACDIRMIN;
+ if ((rv = i_add_option_int("acdirmax", lx_nmd->nmd_acdirmax,
+ options, options_size)) != 0)
+ return (rv);
+ nfs_args->acdirmax = lx_nmd->nmd_acdirmax;
+ nfs_args->flags |= NFSMNT_ACDIRMAX;
+
+ /* We only support nfs with a security type of AUTH_SYS. */
+ nfs_args->nfs_args_ext = NFS_ARGS_EXTB;
+ nfs_args_secdata->secmod = AUTH_SYS;
+ nfs_args_secdata->rpcflavor = AUTH_SYS;
+ nfs_args_secdata->flags = 0;
+ nfs_args_secdata->uid = 0;
+ nfs_args_secdata->data = NULL;
+ nfs_args->nfs_ext_u.nfs_extB.next = NULL;
+
+ /*
+ * The Linux nfs mount command seems to pass an open socket fd
+ * to the kernel during the mount system call. We don't need
+ * this fd on Solaris so just close it.
+ */
+ (void) close(lx_nmd->nmd_fd);
+
+ return (0);
+}
+
+/*
+ * The user-level mount(2) code is only used to support NFS mounts. All other
+ * fstypes are handled in-kernel.
+ */
+long
+lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
+ uintptr_t p5)
+{
+ /* Linux input arguments. */
+ const char *sourcep = (const char *)p1;
+ const char *targetp = (const char *)p2;
+ const char *fstypep = (const char *)p3;
+ unsigned int flags = (unsigned int)p4;
+ const void *datap = (const void *)p5;
+
+ char source[MAXPATHLEN + LX_NMD_MAXHOSTNAMELEN + 1];
+ char target[MAXPATHLEN];
+ char fstype[8], options[MAX_MNTOPT_STR];
+ int sflags, rv;
+ long res;
+
+ lx_nfs_mount_data_t lx_nmd;
+ struct nfs_args nfs_args;
+ struct netbuf nfs_args_addr;
+ struct knetconfig nfs_args_knconf;
+ union fh_buffer nfs_args_fh;
+ struct sec_data nfs_args_secdata;
+ char *sdataptr = NULL;
+ int sdatalen = 0;
+ int vers;
+
+ /* Initialize illumos mount arguments. */
+ sflags = MS_OPTIONSTR;
+ options[0] = '\0';
+ sdatalen = 0;
+
+ /* Copy in parameters that are always present. */
+ rv = uucopystr((void *)sourcep, &source, sizeof (source));
+ if ((rv == -1) || (rv == sizeof (source)))
+ return (-EFAULT);
+
+ rv = uucopystr((void *)targetp, &target, sizeof (target));
+ if ((rv == -1) || (rv == sizeof (target)))
+ return (-EFAULT);
+
+ rv = uucopystr((void *)fstypep, &fstype, sizeof (fstype));
+ if ((rv == -1) || (rv == sizeof (fstype)))
+ return (-EFAULT);
+
+ lx_debug("\tlinux mount source: %s", source);
+ lx_debug("\tlinux mount target: %s", target);
+ lx_debug("\tlinux mount fstype: %s", fstype);
+
+ /* The in-kernel mount code should only call us for an NFS mount. */
+ assert(strcmp(fstype, "nfs") == 0 || strcmp(fstype, "nfs4") == 0);
+
+ /*
+ * While SunOS is picky about mount(2) target paths being absolute,
+ * Linux is not so strict. In order to facilitate this looser
+ * requirement, the cwd is prepended to non-absolute target paths.
+ */
+ if (target[0] != '/') {
+ char *cpath, *buf = NULL;
+ int len;
+
+ if ((cpath = getcwd(NULL, MAXPATHLEN)) == NULL) {
+ return (-ENOMEM);
+ }
+ len = asprintf(&buf, "%s/%s", cpath, target);
+ free(cpath);
+ if (len < 0) {
+ return (-ENOMEM);
+ } else if (len >= MAXPATHLEN) {
+ free(buf);
+ return (-ENAMETOOLONG);
+ }
+ (void) strlcpy(target, buf, sizeof (target));
+ free(buf);
+ }
+
+ /* Make sure we support the requested mount flags. */
+ if ((flags & ~LX_MS_SUPPORTED) != 0) {
+ lx_unsupported("unsupported mount flags: 0x%x", flags);
+ return (-ENOTSUP);
+ }
+
+ /*
+ * Copy in Linux mount options. Note that for older Linux kernels
+ * (pre 2.6.23) the mount options pointer (which normally points to a
+ * string) points to a structure which is populated by the user-level
+ * code after it has done the preliminary RPCs (similar to how our NFS
+ * mount cmd works). For newer kernels the options pointer is just a
+ * string of options. We're unlikely to actually emulate a kernel that
+ * uses the old style but support is kept and handled in
+ * i_make_nfs_args(). The new style handling is implemented in
+ * lx_nfs_mount(). The user-level mount caller is in charge of
+ * determining the format in which it passes the data parameter.
+ */
+ if (datap == NULL)
+ return (-EINVAL);
+ if (uucopy((void *)datap, &vers, sizeof (int)) < 0)
+ return (-errno);
+
+ /*
+ * As described above, the data parameter might be a versioned lx_nmd
+ * structure or (most likely on a modern distribution) it is a string.
+ */
+ if (vers < 1 || vers > 6) {
+ /*
+ * Handle the modern style with options as a string, make the
+ * preliminary RPC calls and do the native mount all within
+ * lx_nfs_mount().
+ */
+ if (uucopystr((void *)datap, options, sizeof (options)) < 0)
+ return (-errno);
+ return (lx_nfs_mount(source, target, fstype, flags, options));
+ }
+
+ /*
+ * This is an old style NFS mount call and we only support v4.
+ */
+ if (vers != 4) {
+ lx_unsupported("unsupported nfs mount request version: %d\n",
+ vers);
+ return (-ENOTSUP);
+ }
+
+ if (uucopy((void *)datap, &lx_nmd, sizeof (lx_nmd)) < 0)
+ return (-errno);
+
+ /*
+ * For illumos NFS mounts, the kernel expects a special structure, but
+ * a pointer to this structure is passed in via an extra parameter
+ * (sdataptr below.)
+ */
+ if ((rv = i_make_nfs_args(&lx_nmd, &nfs_args, &nfs_args_addr,
+ &nfs_args_knconf, &nfs_args_fh, &nfs_args_secdata, fstype, options,
+ sizeof (options))) != 0)
+ return (rv);
+
+ /*
+ * For the following old-style NFS mount we need to tell the mount
+ * system call to expect extra parameters.
+ */
+ sflags |= MS_DATA;
+ sdataptr = (char *)&nfs_args;
+ sdatalen = sizeof (nfs_args);
+
+ /* Linux seems to always allow overlay mounts */
+ sflags |= MS_OVERLAY;
+
+ /* Convert some Linux flags to illumos flags. */
+ if (flags & LX_MS_RDONLY)
+ sflags |= MS_RDONLY;
+ if (flags & LX_MS_NOSUID)
+ sflags |= MS_NOSUID;
+ if (flags & LX_MS_REMOUNT)
+ sflags |= MS_REMOUNT;
+
+ /*
+ * Convert some Linux flags to illumos option strings.
+ */
+ if (flags & LX_MS_STRICTATIME) {
+ /*
+ * The "strictatime" mount option ensures that none of the
+ * weaker atime-related mode options are in effect.
+ */
+ flags &= ~(LX_MS_RELATIME | LX_MS_NOATIME);
+ }
+ if ((flags & LX_MS_NODEV) &&
+ ((rv = i_add_option("nodev", options, sizeof (options))) != 0))
+ return (rv);
+ if ((flags & LX_MS_NOEXEC) &&
+ ((rv = i_add_option("noexec", options, sizeof (options))) != 0))
+ return (rv);
+ if ((flags & LX_MS_NOATIME) &&
+ ((rv = i_add_option("noatime", options, sizeof (options))) != 0))
+ return (rv);
+
+ lx_debug("\tsolaris mount fstype: %s", fstype);
+ lx_debug("\tsolaris mount options: \"%s\"", options);
+
+ res = mount(source, target, sflags, fstype, sdataptr, sdatalen,
+ options, sizeof (options));
+
+ return ((res == 0) ? 0 : -errno);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c b/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c
new file mode 100644
index 0000000000..ca90a80e5f
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c
@@ -0,0 +1,1506 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * NFS mount syscall support
+ *
+ * The illumos NFS user-level mount code encapsulates a significant amount of
+ * functionality into librpc and libnsl. This includes a variety of functions
+ * to perform lookups in the various /etc configuration files. For v2/v3 in
+ * particular, the library code must make a call to the server's 'mountd' to
+ * obtain a file handle to pass into the mount(2) syscall. There can be a
+ * variety of calls to the server's 'rpcbind' made by the libraries during the
+ * preliminaries before calling mount(2). All of the logic for falling back
+ * when determining which version to use (when none is explicitly provided), as
+ * well as retries when the server is not responding, is encapsulated in the
+ * libraries.
+ *
+ * For Linux, much of this functionality is also included in the user-level
+ * mount code, and thus not of concern to us at the Linux syscall level. The
+ * major difference is that the RPC to the 'mountd' to get the file handle for
+ * v2/v3 is made within the kernel as part of the mount(2) syscall. However,
+ * the Linux user-level code will perform all of the logical name lookups (e.g.
+ * hostname to IP address), will make the 'rpcbind' call to determine the
+ * server's 'mountd' protocol and port, and will handle the retry logic.
+ *
+ * Thus, when we reach our code here, we don't need to do any name lookups in
+ * any of the /etc files and we never need to call 'rpcbind'. We only need to
+ * make the RPC to get the file handle for v2/v3 mounts. We're still dependent
+ * on librpc/libnsl to make this RPC, but our overall complexity is much less
+ * than what is seen with the native mount library usage. In addition, we also
+ * have to convert the Linux mount arguments into our native format. Because
+ * we're really just making the RPC to get a file handle and reformatting the
+ * mount arguments, this code should be amenable to living in-kernel at some
+ * point.
+ *
+ * Finally, in most of the functions below, when the code refers to the
+ * hostname we're really working with the IP addr that the Linux user-level
+ * mount command passed in to us.
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#define NFSCLIENT
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/mount.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <nfs/nfs.h>
+#include <nfs/mount.h>
+#include <rpcsvc/mount.h>
+#include <sys/pathconf.h>
+#include <netdir.h>
+#include <netconfig.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <nfs/nfs_sec.h>
+#include <rpcsvc/daemon_utils.h>
+#include <rpcsvc/nfs4_prot.h>
+#include <limits.h>
+#include <nfs/nfssys.h>
+#include <strings.h>
+#include <assert.h>
+#include <sys/lx_mount.h>
+#include <sys/lx_misc.h>
+#include <sys/syscall.h>
+
+#ifndef NFS_VERSMAX
+#define NFS_VERSMAX 4
+#endif
+#ifndef NFS_VERSMIN
+#define NFS_VERSMIN 2
+#endif
+
+#define RET_OK 0
+#define RET_RETRY 32
+#define RET_ERR 33
+#define RET_PROTOUNSUPP 34
+#define RET_MNTERR 1000
+#define ERR_PROTO_NONE 0
+#define ERR_PROTO_INVALID 901
+#define ERR_PROTO_UNSUPP 902
+#define ERR_NETPATH 903
+#define ERR_NOHOST 904
+#define ERR_RPCERROR 905
+
+typedef struct err_ret {
+ int error_type;
+ int error_value;
+} err_ret_t;
+
+#define SET_ERR_RET(errst, etype, eval) \
+ { \
+ (errst)->error_type = etype; \
+ (errst)->error_value = eval; \
+ }
+
+/*
+ * Built-in netconfig table.
+ */
+#define N_NETCONF_ENTS 4
+static struct netconfig nca[N_NETCONF_ENTS] = {
+ {"udp6", NC_TPI_CLTS, 1, "inet6", "udp", "/dev/udp6", 0, NULL},
+ {"tcp6", NC_TPI_COTS_ORD, 1, "inet6", "tcp", "/dev/tcp6", 0, NULL},
+ {"udp", NC_TPI_CLTS, 1, "inet", "udp", "/dev/udp", 0, NULL},
+ {"tcp", NC_TPI_COTS_ORD, 1, "inet", "tcp", "/dev/tcp", 0, NULL}
+};
+
+/*
+ * Mapping table of Linux NFS mount options to the corresponding Illumos
+ * option. The nmo_argtyp field tells us how to handle the argument.
+ */
+typedef enum map_mount_opt_type {
+ MOUNT_OPT_INVALID = 0,
+ MOUNT_OPT_PASTHRU = 1,
+ MOUNT_OPT_IGNORE = 2,
+ MOUNT_OPT_TOKEN = 3,
+ MOUNT_OPT_HAS_ARG = 4
+} map_mount_opt_type_t;
+
+typedef struct nfs_map_opt {
+ char *nmo_lx_opt;
+ char *nmo_il_opt;
+ map_mount_opt_type_t nmo_argtyp;
+} nfs_map_opt_t;
+
+static nfs_map_opt_t nmo_tab[] = {
+ {"ac", NULL, MOUNT_OPT_IGNORE},
+ {"acdirmax", NULL, MOUNT_OPT_PASTHRU},
+ {"acdirmin", NULL, MOUNT_OPT_PASTHRU},
+ {"acl", NULL, MOUNT_OPT_INVALID},
+ {"acregmax", NULL, MOUNT_OPT_PASTHRU},
+ {"acregmin", NULL, MOUNT_OPT_PASTHRU},
+ {"actimeo", NULL, MOUNT_OPT_PASTHRU},
+ {"bg", NULL, MOUNT_OPT_IGNORE},
+ {"cto", NULL, MOUNT_OPT_IGNORE},
+ {"fg", NULL, MOUNT_OPT_IGNORE},
+ {"fsc", NULL, MOUNT_OPT_IGNORE},
+ {"hard", NULL, MOUNT_OPT_PASTHRU},
+ {"intr", NULL, MOUNT_OPT_PASTHRU},
+ {"lock", NULL, MOUNT_OPT_IGNORE},
+ {"lookupcache", NULL, MOUNT_OPT_INVALID},
+ {"local_lock=%s", NULL, MOUNT_OPT_INVALID },
+ {"migration", NULL, MOUNT_OPT_INVALID},
+ {"minorversion", NULL, MOUNT_OPT_INVALID},
+ {"mountaddr", NULL, MOUNT_OPT_INVALID},
+ {"mounthost", NULL, MOUNT_OPT_INVALID},
+ {"mountport", NULL, MOUNT_OPT_PASTHRU},
+ {"mountproto", NULL, MOUNT_OPT_PASTHRU},
+ {"mountvers", NULL, MOUNT_OPT_PASTHRU},
+ {"namlen", NULL, MOUNT_OPT_INVALID},
+ {"nfsvers", NULL, MOUNT_OPT_INVALID},
+ {"noac", NULL, MOUNT_OPT_PASTHRU},
+ {"noacl", NULL, MOUNT_OPT_INVALID},
+ {"nocto", NULL, MOUNT_OPT_PASTHRU},
+ {"nofsc", NULL, MOUNT_OPT_IGNORE},
+ {"nointr", NULL, MOUNT_OPT_PASTHRU},
+ {"nolock", "llock", MOUNT_OPT_TOKEN},
+ {"nomigration", NULL, MOUNT_OPT_INVALID},
+ {"noposix", NULL, MOUNT_OPT_IGNORE},
+ {"nordirplus", NULL, MOUNT_OPT_IGNORE},
+ {"noresvport", NULL, MOUNT_OPT_INVALID},
+ {"nosharecache", NULL, MOUNT_OPT_IGNORE},
+ {"port", NULL, MOUNT_OPT_PASTHRU},
+ {"posix", NULL, MOUNT_OPT_PASTHRU},
+ {"proto", NULL, MOUNT_OPT_PASTHRU},
+ {"rdirplus", NULL, MOUNT_OPT_IGNORE},
+ {"rdma", "proto=rdma", MOUNT_OPT_TOKEN},
+ {"resvport", NULL, MOUNT_OPT_IGNORE},
+ {"retrans", NULL, MOUNT_OPT_PASTHRU},
+ {"retry", NULL, MOUNT_OPT_IGNORE},
+ {"rsize", NULL, MOUNT_OPT_PASTHRU},
+ {"sec", NULL, MOUNT_OPT_PASTHRU},
+ {"sharecache", NULL, MOUNT_OPT_IGNORE},
+ {"sloppy", NULL, MOUNT_OPT_IGNORE},
+ {"soft", NULL, MOUNT_OPT_PASTHRU},
+ {"tcp", "proto=tcp", MOUNT_OPT_TOKEN},
+ {"timeo", NULL, MOUNT_OPT_PASTHRU},
+ {"udp", "proto=udp", MOUNT_OPT_TOKEN},
+ {"vers", NULL, MOUNT_OPT_PASTHRU},
+ {"wsize", NULL, MOUNT_OPT_PASTHRU},
+ {NULL, NULL, MOUNT_OPT_INVALID}
+};
+
+/*
+ * This struct is used to keep track of misc. variables which are set deep
+ * in one function then referenced someplace else. We pass this around to
+ * avoid the use of global variables as is done the the NFS mount command.
+ *
+ * The nfsvers variables control the NFS version number to be used.
+ *
+ * nmd_nfsvers defaults to 0 which means to use the highest number that
+ * both the client and the server support. It can also be set to
+ * a particular value, either 2, 3, or 4 to indicate the version
+ * number of choice. If the server (or the client) do not support
+ * the version indicated, then the mount attempt will be failed.
+ */
+typedef struct nfs_mnt_data {
+ int nmd_posix;
+ ushort_t nmd_nfs_port;
+ char *nmd_nfs_proto;
+ ushort_t nmd_mnt_port;
+ char *nmd_mnt_proto;
+ char *nmd_fstype;
+ seconfig_t nmd_nfs_sec;
+ int nmd_sec_opt; /* any security option ? */
+ int nmd_nolock_opt; /* 'nolock' specified */
+ rpcvers_t nmd_mnt_vers;
+ rpcvers_t nmd_nfsvers;
+} nfs_mnt_data_t;
+
+/* number of transports to try */
+#define MNT_PREF_LISTLEN 2
+#define FIRST_TRY 1
+#define SECOND_TRY 2
+
+#define BIGRETRY 10000
+
+/* maximum length of RPC header for NFS messages */
+#define NFS_RPC_HDR 432
+
+extern int __clnt_bindresvport(CLIENT *);
+
+static int set_args(int *, struct nfs_args *, char *, char *, nfs_mnt_data_t *);
+static int get_fh(struct nfs_args *, char *, char *, nfs_mnt_data_t *);
+static int make_secure(struct nfs_args *, nfs_mnt_data_t *);
+static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
+ nfs_mnt_data_t *);
+
+static void
+log_err(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[128];
+ int fd;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, sizeof (buf), fmt, ap);
+ va_end(ap);
+
+ if ((fd = open("/dev/conslog", O_WRONLY)) != -1) {
+ (void) write(fd, buf, strlen(buf));
+ (void) close(fd);
+ }
+}
+
+static int
+i_add_option(char *option, char *buf, size_t buf_size)
+{
+ int len;
+ char *fmt_str = NULL;
+
+ if (buf[0] == '\0') {
+ fmt_str = "%s";
+ } else {
+ fmt_str = ",%s";
+ }
+
+ len = strlen(buf);
+ buf_size -= len;
+ buf += len;
+
+ /*LINTED*/
+ if (snprintf(buf, buf_size, fmt_str, option) > (buf_size - 1))
+ return (-EOVERFLOW);
+ return (0);
+}
+
+/*
+ * These options were initially derived from uts/common/fs/nfs/nfs_dlinet.c
+ * but have been extended to add additional Linux options.
+ */
+static char *optlist[] = {
+#define OPT_RO 0
+ MNTOPT_RO,
+#define OPT_RW 1
+ MNTOPT_RW,
+#define OPT_QUOTA 2
+ MNTOPT_QUOTA,
+#define OPT_NOQUOTA 3
+ MNTOPT_NOQUOTA,
+#define OPT_SOFT 4
+ MNTOPT_SOFT,
+#define OPT_HARD 5
+ MNTOPT_HARD,
+#define OPT_SUID 6
+ MNTOPT_SUID,
+#define OPT_NOSUID 7
+ MNTOPT_NOSUID,
+#define OPT_GRPID 8
+ MNTOPT_GRPID,
+#define OPT_REMOUNT 9
+ MNTOPT_REMOUNT,
+#define OPT_NOSUB 10
+ MNTOPT_NOSUB,
+#define OPT_INTR 11
+ MNTOPT_INTR,
+#define OPT_NOINTR 12
+ MNTOPT_NOINTR,
+#define OPT_PORT 13
+ MNTOPT_PORT,
+#define OPT_SECURE 14
+ MNTOPT_SECURE,
+#define OPT_RSIZE 15
+ MNTOPT_RSIZE,
+#define OPT_WSIZE 16
+ MNTOPT_WSIZE,
+#define OPT_TIMEO 17
+ MNTOPT_TIMEO,
+#define OPT_RETRANS 18
+ MNTOPT_RETRANS,
+#define OPT_ACTIMEO 19
+ MNTOPT_ACTIMEO,
+#define OPT_ACREGMIN 20
+ MNTOPT_ACREGMIN,
+#define OPT_ACREGMAX 21
+ MNTOPT_ACREGMAX,
+#define OPT_ACDIRMIN 22
+ MNTOPT_ACDIRMIN,
+#define OPT_ACDIRMAX 23
+ MNTOPT_ACDIRMAX,
+#define OPT_BG 24
+ MNTOPT_BG,
+#define OPT_FG 25
+ MNTOPT_FG,
+#define OPT_RETRY 26
+ MNTOPT_RETRY,
+#define OPT_NOAC 27
+ MNTOPT_NOAC,
+#define OPT_NOCTO 28
+ MNTOPT_NOCTO,
+#define OPT_LLOCK 29
+ MNTOPT_LLOCK,
+#define OPT_POSIX 30
+ MNTOPT_POSIX,
+#define OPT_VERS 31
+ MNTOPT_VERS,
+#define OPT_PROTO 32
+ MNTOPT_PROTO,
+#define OPT_SEMISOFT 33
+ MNTOPT_SEMISOFT,
+#define OPT_NOPRINT 34
+ MNTOPT_NOPRINT,
+#define OPT_SEC 35
+ MNTOPT_SEC,
+#define OPT_LARGEFILES 36
+ MNTOPT_LARGEFILES,
+#define OPT_NOLARGEFILES 37
+ MNTOPT_NOLARGEFILES,
+#define OPT_PUBLIC 38
+ MNTOPT_PUBLIC,
+#define OPT_DIRECTIO 39
+ MNTOPT_FORCEDIRECTIO,
+#define OPT_NODIRECTIO 40
+ MNTOPT_NOFORCEDIRECTIO,
+#define OPT_XATTR 41
+ MNTOPT_XATTR,
+#define OPT_NOXATTR 42
+ MNTOPT_NOXATTR,
+#define OPT_DEVICES 43
+ MNTOPT_DEVICES,
+#define OPT_NODEVICES 44
+ MNTOPT_NODEVICES,
+#define OPT_SETUID 45
+ MNTOPT_SETUID,
+#define OPT_NOSETUID 46
+ MNTOPT_NOSETUID,
+#define OPT_EXEC 47
+ MNTOPT_EXEC,
+#define OPT_NOEXEC 48
+ MNTOPT_NOEXEC,
+#define OPT_MNT_VERS 49
+ "mountvers",
+#define OPT_MNT_PORT 50
+ "mountport",
+#define OPT_MNT_PROTO 51
+ "mountproto",
+
+ NULL
+};
+
+static int
+convert_int(int *val, char *str)
+{
+ long lval;
+
+ if (str == NULL || !isdigit(*str))
+ return (-1);
+
+ lval = strtol(str, &str, 10);
+ if (*str != '\0' || lval > INT_MAX)
+ return (-2);
+
+ *val = (int)lval;
+ return (0);
+}
+
+static int
+set_args(int *mntflags, struct nfs_args *args, char *fshost, char *mntopts,
+ nfs_mnt_data_t *nmdp)
+{
+ char *saveopt, *optstr, *opts, *newopts, *val;
+ int num;
+ int largefiles = 0;
+ int invalid = 0;
+ int attrpref = 0;
+ int optlen, oldlen;
+
+ args->flags = NFSMNT_INT; /* default is "intr" */
+ args->flags |= NFSMNT_HOSTNAME;
+ args->flags |= NFSMNT_NEWARGS; /* using extented nfs_args structure */
+ args->hostname = fshost;
+
+ oldlen = strlen(mntopts);
+ optstr = opts = strdup(mntopts);
+ if (opts == NULL)
+ return (-ENOMEM);
+ /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
+ optlen = oldlen + sizeof (MNTOPT_XATTR) + 1;
+ if (optlen > MAX_MNTOPT_STR)
+ return (-EINVAL);
+
+ newopts = malloc(optlen);
+ if (opts == NULL || newopts == NULL) {
+ if (opts)
+ free(opts);
+ if (newopts)
+ free(newopts);
+ return (-EINVAL);
+ }
+ newopts[0] = '\0';
+
+ while (*opts) {
+ invalid = 0;
+ saveopt = opts;
+ switch (getsubopt(&opts, optlist, &val)) {
+ case OPT_RO:
+ *mntflags |= MS_RDONLY;
+ break;
+ case OPT_RW:
+ *mntflags &= ~(MS_RDONLY);
+ break;
+ case OPT_QUOTA:
+ case OPT_NOQUOTA:
+ break;
+ case OPT_SOFT:
+ args->flags |= NFSMNT_SOFT;
+ args->flags &= ~(NFSMNT_SEMISOFT);
+ break;
+ case OPT_SEMISOFT:
+ args->flags |= NFSMNT_SOFT;
+ args->flags |= NFSMNT_SEMISOFT;
+ break;
+ case OPT_HARD:
+ args->flags &= ~(NFSMNT_SOFT);
+ args->flags &= ~(NFSMNT_SEMISOFT);
+ break;
+ case OPT_SUID:
+ *mntflags &= ~(MS_NOSUID);
+ break;
+ case OPT_NOSUID:
+ *mntflags |= MS_NOSUID;
+ break;
+ case OPT_GRPID:
+ args->flags |= NFSMNT_GRPID;
+ break;
+ case OPT_REMOUNT:
+ *mntflags |= MS_REMOUNT;
+ break;
+ case OPT_INTR:
+ args->flags |= NFSMNT_INT;
+ break;
+ case OPT_NOINTR:
+ args->flags &= ~(NFSMNT_INT);
+ break;
+ case OPT_NOAC:
+ args->flags |= NFSMNT_NOAC;
+ break;
+ case OPT_PORT:
+ if (convert_int(&num, val) != 0)
+ goto badopt;
+ nmdp->nmd_nfs_port = num;
+ break;
+
+ case OPT_NOCTO:
+ args->flags |= NFSMNT_NOCTO;
+ break;
+
+ case OPT_RSIZE:
+ if (convert_int(&args->rsize, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_RSIZE;
+ break;
+ case OPT_WSIZE:
+ if (convert_int(&args->wsize, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_WSIZE;
+ break;
+ case OPT_TIMEO:
+ if (convert_int(&args->timeo, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_TIMEO;
+ break;
+ case OPT_RETRANS:
+ if (convert_int(&args->retrans, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_RETRANS;
+ break;
+ case OPT_ACTIMEO:
+ if (convert_int(&args->acregmax, val) != 0)
+ goto badopt;
+ args->acdirmin = args->acregmin = args->acdirmax
+ = args->acregmax;
+ args->flags |= NFSMNT_ACDIRMAX;
+ args->flags |= NFSMNT_ACREGMAX;
+ args->flags |= NFSMNT_ACDIRMIN;
+ args->flags |= NFSMNT_ACREGMIN;
+ break;
+ case OPT_ACREGMIN:
+ if (convert_int(&args->acregmin, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_ACREGMIN;
+ break;
+ case OPT_ACREGMAX:
+ if (convert_int(&args->acregmax, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_ACREGMAX;
+ break;
+ case OPT_ACDIRMIN:
+ if (convert_int(&args->acdirmin, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_ACDIRMIN;
+ break;
+ case OPT_ACDIRMAX:
+ if (convert_int(&args->acdirmax, val) != 0)
+ goto badopt;
+ args->flags |= NFSMNT_ACDIRMAX;
+ break;
+ case OPT_BG:
+ /* Ignored as does Linux kernel */
+ break;
+ case OPT_FG:
+ /* Ignored as does Linux kernel */
+ break;
+ case OPT_RETRY:
+ /* Ignored as does Linux kernel */
+ break;
+ case OPT_LLOCK:
+ args->flags |= NFSMNT_LLOCK;
+ break;
+ case OPT_POSIX:
+ nmdp->nmd_posix = 1;
+ break;
+ case OPT_VERS:
+ if (convert_int(&num, val) != 0)
+ goto badopt;
+ nmdp->nmd_nfsvers = (rpcvers_t)num;
+ break;
+ case OPT_PROTO:
+ if (val == NULL)
+ goto badopt;
+
+ nmdp->nmd_nfs_proto = (char *)malloc(strlen(val)+1);
+ if (!nmdp->nmd_nfs_proto)
+ return (-EINVAL);
+
+ (void) strncpy(nmdp->nmd_nfs_proto, val, strlen(val)+1);
+ break;
+
+ case OPT_NOPRINT:
+ args->flags |= NFSMNT_NOPRINT;
+ break;
+
+ case OPT_LARGEFILES:
+ largefiles = 1;
+ break;
+
+ case OPT_NOLARGEFILES:
+ free(optstr);
+ return (-EINVAL);
+
+ case OPT_SEC:
+ if (val == NULL)
+ return (-EINVAL);
+ /*
+ * We initialize the nfs_sec struct as if we had the
+ * basic /etc/nfssec.conf file.
+ */
+ if (strcmp(val, "none") == 0) {
+ (void) strlcpy(nmdp->nmd_nfs_sec.sc_name,
+ "none", MAX_NAME_LEN);
+ nmdp->nmd_nfs_sec.sc_nfsnum =
+ nmdp->nmd_nfs_sec.sc_rpcnum = 0;
+ } else if (strcmp(val, "sys") == 0) {
+ (void) strlcpy(nmdp->nmd_nfs_sec.sc_name,
+ "sys", MAX_NAME_LEN);
+ nmdp->nmd_nfs_sec.sc_nfsnum =
+ nmdp->nmd_nfs_sec.sc_rpcnum = 1;
+ } else {
+ return (-EINVAL);
+ }
+ nmdp->nmd_sec_opt++;
+ break;
+
+ case OPT_DIRECTIO:
+ args->flags |= NFSMNT_DIRECTIO;
+ break;
+
+ case OPT_NODIRECTIO:
+ args->flags &= ~(NFSMNT_DIRECTIO);
+ break;
+
+ case OPT_XATTR:
+ case OPT_NOXATTR:
+ /*
+ * VFS options; just need to get them into the
+ * new mount option string and note we've seen them
+ */
+ attrpref = 1;
+ break;
+
+ case OPT_MNT_VERS:
+ if (convert_int(&num, val) != 0)
+ goto badopt;
+ nmdp->nmd_mnt_vers = (rpcvers_t)num;
+ invalid = 1; /* Invalid as a native option */
+ break;
+
+ case OPT_MNT_PORT:
+ if (convert_int(&num, val) != 0)
+ goto badopt;
+ nmdp->nmd_mnt_port = num;
+ invalid = 1; /* Invalid as a native option */
+ break;
+
+ case OPT_MNT_PROTO:
+ if (val == NULL)
+ goto badopt;
+ nmdp->nmd_mnt_proto = strdup(val);
+ if (nmdp->nmd_mnt_proto == NULL)
+ return (-ENOMEM);
+ invalid = 1; /* Invalid as a native option */
+ break;
+
+ default:
+ invalid = 1;
+ break;
+ }
+ if (!invalid) {
+ if (newopts[0] != '\0') {
+ (void) strlcat(newopts, ",", optlen);
+ }
+ (void) strlcat(newopts, saveopt, optlen);
+ }
+ }
+ /* Default is to turn extended attrs on */
+ if (!attrpref) {
+ if (newopts[0]) {
+ (void) strlcat(newopts, ",", optlen);
+ }
+ (void) strlcat(newopts, MNTOPT_XATTR, optlen);
+ }
+ (void) strlcpy(mntopts, newopts, oldlen);
+ free(newopts);
+ free(optstr);
+
+ /* ensure that only one secure mode is requested */
+ if (nmdp->nmd_sec_opt > 1)
+ return (-EINVAL);
+
+ /* ensure that the user isn't trying to get large files over V2 */
+ if (nmdp->nmd_nfsvers == NFS_VERSION && largefiles)
+ return (-EINVAL);
+
+ if (nmdp->nmd_nfsvers == NFS_V4) {
+ /*
+ * NFSv4 specifies the TCP protocol and port 2049 - default to
+ * these. The user-level mount code is not expected to pass
+ * these in, but if it did, validate the proto value.
+ */
+ if (nmdp->nmd_nfs_proto == NULL) {
+ nmdp->nmd_nfs_proto = strdup(NC_TCP);
+ if (nmdp->nmd_nfs_proto == NULL)
+ return (-ENOMEM);
+
+ } else if (strcmp(nmdp->nmd_nfs_proto, NC_TCP) != 0) {
+ return (-EINVAL);
+ }
+
+ } else {
+ /*
+ * The user-level mount code normally passes in the proto, but
+ * if it didn't for some reason, use a sensible default.
+ * Otherwise we normally just validate the proto value and we
+ * only support TCP or UDP.
+ */
+ if (nmdp->nmd_nfs_proto == NULL) {
+ nmdp->nmd_nfs_proto = strdup(NC_TCP);
+ if (nmdp->nmd_nfs_proto == NULL)
+ return (-ENOMEM);
+
+ } else if (strcmp(nmdp->nmd_nfs_proto, NC_TCP) != 0 &&
+ strcmp(nmdp->nmd_nfs_proto, NC_UDP) != 0) {
+ return (-EINVAL);
+ }
+ }
+
+ /*
+ * The user-level mount code only passes the port when it is
+ * non-standard.
+ */
+ if (nmdp->nmd_nfs_port == 0) {
+ nmdp->nmd_nfs_port = NFS_PORT;
+ }
+
+ return (0);
+
+badopt:
+ free(optstr);
+ return (-EINVAL);
+}
+
+static int
+make_secure(struct nfs_args *args, nfs_mnt_data_t *nmdp)
+{
+ sec_data_t *secdata;
+
+ /*
+ * Check to see if any secure mode is requested. If not, use default
+ * security mode. Note: we currently only support sec=none and sec=sys.
+ */
+ if (nmdp->nmd_sec_opt == 0) {
+ /* AUTH_UNIX is the default. */
+ (void) strlcpy(nmdp->nmd_nfs_sec.sc_name, "sys", MAX_NAME_LEN);
+ nmdp->nmd_nfs_sec.sc_nfsnum = nmdp->nmd_nfs_sec.sc_rpcnum = 1;
+ args->flags |= NFSMNT_SECDEFAULT;
+ }
+
+ secdata = malloc(sizeof (sec_data_t));
+ if (secdata == NULL)
+ return (-ENOMEM);
+
+ (void) memset(secdata, 0, sizeof (sec_data_t));
+
+ secdata->secmod = nmdp->nmd_nfs_sec.sc_nfsnum;
+ secdata->rpcflavor = nmdp->nmd_nfs_sec.sc_rpcnum;
+ secdata->uid = nmdp->nmd_nfs_sec.sc_uid;
+ secdata->flags = 0;
+ secdata->data = NULL;
+
+ args->nfs_args_ext = NFS_ARGS_EXTB;
+ args->nfs_ext_u.nfs_extB.secdata = secdata;
+
+ return (0);
+}
+
+/*
+ * Use our built-in netconfig table to lookup and construct a netconfig struct
+ * for the given netid.
+ */
+static struct netconfig *
+get_netconf(char *id)
+{
+ int i;
+ struct netconfig *nconf, *np;
+
+ if ((nconf = calloc(1, sizeof (struct netconfig))) == NULL)
+ return (NULL);
+
+ for (i = 0; i < N_NETCONF_ENTS; i++) {
+ np = &nca[i];
+ if (strcmp(np->nc_netid, id) != 0)
+ continue;
+
+ nconf->nc_semantics = np->nc_semantics;
+ if ((nconf->nc_netid = strdup(np->nc_netid)) == NULL)
+ goto out;
+ if ((nconf->nc_protofmly = strdup(np->nc_protofmly)) == NULL)
+ goto out;
+ if ((nconf->nc_proto = strdup(np->nc_proto)) == NULL)
+ goto out;
+ if ((nconf->nc_device = strdup(np->nc_device)) == NULL)
+ goto out;
+
+ return (nconf);
+ }
+
+out:
+ freenetconfigent(nconf);
+ return (NULL);
+}
+
+/*
+ * If the user provided a logical name for the NFS server, then the user-level
+ * mount command will have already resolved that name and passed it in using
+ * the 'addr' option (see convert_nfs_arg_str where we've already handled this).
+ * We construct a netbuf from that provided IP and a given port option.
+ *
+ * Note: this code may need to be revisited when we add IPv6 support.
+ */
+static struct netbuf *
+get_netbuf(struct netconfig *nconf, char *ip, ushort_t port)
+{
+ char buf[64];
+
+ assert(port != 0);
+ (void) snprintf(buf, sizeof (buf), "%s.%d.%d", ip,
+ port >> 8 & 0xff, port & 0xff);
+ return (uaddr2taddr(nconf, buf));
+}
+
+/*
+ * Construct a CLIENT handle to talk to the mountd without having to contact
+ * the rpcbind daemon on the server. This works for both the TCP and UDP cases,
+ * but it is primarily intended to the handle the TCP case. As an aside, note
+ * that TCP is never used by the native NFS mount client, even when the
+ * 'proto=tcp' argument is given to the mount command. The native mount code
+ * always uses UDP to get a file handle from the mountd.
+ */
+static CLIENT *
+get_mountd_client(char *fshost, nfs_mnt_data_t *nmdp, int *fdp)
+{
+ struct netconfig *nconf;
+ struct netbuf *srvaddr;
+ CLIENT *cl = NULL;
+ rpcvers_t vers;
+ int fd;
+ struct t_bind *tbind = NULL;
+ struct t_info tinfo;
+
+ vers = nmdp->nmd_mnt_vers;
+ *fdp = -1;
+
+ if ((nconf = get_netconf(nmdp->nmd_mnt_proto)) == NULL)
+ return (NULL);
+
+ if ((srvaddr = get_netbuf(nconf, fshost, nmdp->nmd_mnt_port)) == NULL) {
+ freenetconfigent(nconf);
+ return (NULL);
+ }
+
+ tinfo.tsdu = 0;
+ if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1)
+ goto done;
+
+ /* LINTED pointer alignment */
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL) {
+ (void) t_close(fd);
+ goto done;
+ }
+
+ /* assign our srvaddr to tbind addr */
+ (void) memcpy(tbind->addr.buf, srvaddr->buf, srvaddr->len);
+ tbind->addr.len = srvaddr->len;
+
+ /*
+ * For compatibility, the mountd call to get the file handle must come
+ * from a privileged port.
+ */
+ (void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
+
+ cl = clnt_tli_create(fd, nconf, &tbind->addr, MOUNTPROG, vers, 0, 0);
+ if (cl == NULL) {
+ (void) t_close(fd);
+ /*
+ * Unfortunately, a failure in the:
+ * clnt_tli_create -> set_up_connection -> t_connect
+ * call path doesn't return any useful information about why we
+ * had an error. We basically see the following rpc_createerr
+ * status for a variety of conditions (e.g. invalid port, no
+ * service at IP, timeout, etc.):
+ * rpc_createerr.cf_stat == RPC_TLIERROR
+ * rpc_createerr.cf_error.re_terrno == 9 (TLOOK)
+ * rpc_createerr.cf_error.re_errno == 0
+ */
+ } else {
+ *fdp = fd;
+ }
+
+done:
+ if (tbind != NULL)
+ (void) t_free((char *)tbind, T_BIND);
+ free(srvaddr->buf);
+ free(srvaddr);
+ freenetconfigent(nconf);
+
+ return (cl);
+}
+
+static int
+get_fh_cleanup(CLIENT *cl, int fd, int err)
+{
+ if (cl != NULL)
+ clnt_destroy(cl);
+ if (fd != -1)
+ (void) t_close(fd);
+ assert(err <= 0);
+ return (err);
+}
+
+/*
+ * Get fhandle of remote path from server's mountd. This is only applicable to
+ * v2 or v3.
+ */
+static int
+get_fh(struct nfs_args *args, char *fshost, char *fspath, nfs_mnt_data_t *nmdp)
+{
+ struct fhstatus fhs;
+ struct mountres3 mountres3;
+ struct pathcnf p;
+ nfs_fh3 *fh3p;
+ struct timeval timeout = { 25, 0};
+ CLIENT *cl = NULL;
+ int fd = -1;
+ enum clnt_stat rpc_stat;
+ int count, i, *auths;
+
+ bzero(&fhs, sizeof (fhs));
+ bzero(&mountres3, sizeof (mountres3));
+ bzero(&p, sizeof (p));
+
+ /*
+ * The user-level mount code should have contacted the server's rpcbind
+ * daemon and passed us the mount protocol and port.
+ */
+ if (nmdp->nmd_mnt_port == 0 || nmdp->nmd_mnt_proto == NULL ||
+ nmdp->nmd_mnt_vers == 0) {
+ return (-EAGAIN);
+ }
+
+ cl = get_mountd_client(fshost, nmdp, &fd);
+ if (cl == NULL) {
+ /*
+ * As noted in get_mountd_client, we don't get a good indication
+ * as to why the connection failed. Linux returns ETIMEDOUT
+ * under many of the same conditions, and our native code notes
+ * that this is a common reason, so we do that here too.
+ */
+ return (-ETIMEDOUT);
+ }
+
+ if ((cl->cl_auth = authsys_create_default()) == NULL) {
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+
+ if (nmdp->nmd_mnt_vers == 2) {
+ rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
+ (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
+ if (rpc_stat != RPC_SUCCESS) {
+ log_err("%s:%s: server not responding %s\n",
+ fshost, fspath, clnt_sperror(cl, ""));
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+
+ if ((errno = fhs.fhs_status) != MNT_OK) {
+ return (get_fh_cleanup(cl, fd, -fhs.fhs_status));
+ }
+ args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
+ if (args->fh == NULL)
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+
+ (void) memcpy((caddr_t)args->fh,
+ (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
+ sizeof (fhs.fhstatus_u.fhs_fhandle));
+ if (!errno && nmdp->nmd_posix) {
+ rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
+ xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
+ (caddr_t)&p, timeout);
+ if (rpc_stat != RPC_SUCCESS) {
+ log_err("%s:%s: server not responding %s\n",
+ fshost, fspath, clnt_sperror(cl, ""));
+ free(args->fh);
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+ if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
+ free(args->fh);
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+ args->flags |= NFSMNT_POSIX;
+ args->pathconf = malloc(sizeof (p));
+ if (args->pathconf == NULL) {
+ free(args->fh);
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+ (void) memcpy((caddr_t)args->pathconf, (caddr_t)&p,
+ sizeof (p));
+ }
+
+ } else { /* nmdp->nmd_mnt_vers == 3 */
+
+ rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
+ (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3,
+ timeout);
+ if (rpc_stat != RPC_SUCCESS) {
+ log_err("%s:%s: server not responding %s\n",
+ fshost, fspath, clnt_sperror(cl, ""));
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+
+ /*
+ * Assume here that most of the MNT3ERR_*
+ * codes map into E* errors. See the nfsstat enum for values.
+ */
+ if ((errno = mountres3.fhs_status) != MNT_OK) {
+ return (get_fh_cleanup(cl, fd, -mountres3.fhs_status));
+ }
+
+ fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
+ if (fh3p == NULL)
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+
+ fh3p->fh3_length =
+ mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
+ (void) memcpy(fh3p->fh3_u.data,
+ mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
+ fh3p->fh3_length);
+ args->fh = (caddr_t)fh3p;
+ nmdp->nmd_fstype = MNTTYPE_NFS3;
+
+ /*
+ * If "sec=flavor" is a mount option, check if the server
+ * supports the "flavor". If the server does not support the
+ * flavor, return error. It is unlikely that the server will
+ * not support "sys", although "none" may not be allowed.
+ */
+ auths =
+ mountres3.mountres3_u.mountinfo.auth_flavors
+ .auth_flavors_val;
+ count =
+ mountres3.mountres3_u.mountinfo.auth_flavors
+ .auth_flavors_len;
+
+ if (count <= 0) {
+ return (get_fh_cleanup(cl, fd, -EAGAIN));
+ }
+
+ if (nmdp->nmd_sec_opt) {
+ for (i = 0; i < count; i++) {
+ if (auths[i] == nmdp->nmd_nfs_sec.sc_nfsnum)
+ break;
+ }
+ if (i == count)
+ return (get_fh_cleanup(cl, fd, -EACCES));
+ } else {
+ /* AUTH_SYS is our default. */
+ (void) strlcpy(nmdp->nmd_nfs_sec.sc_name, "sys",
+ MAX_NAME_LEN);
+ nmdp->nmd_nfs_sec.sc_nfsnum =
+ nmdp->nmd_nfs_sec.sc_rpcnum = 1;
+ }
+ }
+
+ return (get_fh_cleanup(cl, fd, 0));
+}
+
+/*
+ * Fill in the address for the server's NFS service and fill in a knetconfig
+ * structure for the transport that the service is available on.
+ */
+static int
+getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
+ nfs_mnt_data_t *nmdp)
+{
+ struct stat sb;
+ struct netconfig *nconf = NULL;
+ struct knetconfig *knconfp;
+ struct t_info tinfo;
+ err_ret_t addr_error;
+
+ SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
+
+ /*
+ * Given the values passed in from the user-land mount command (or our
+ * built-in defaults), we should have the necessary NFS host address
+ * info. We have already validated that we have a supported
+ * nmd_nfs_proto.
+ */
+ assert(nmdp->nmd_nfs_port != 0);
+ assert(nmdp->nmd_nfs_proto != NULL);
+ nconf = get_netconf(nmdp->nmd_nfs_proto);
+ assert(nconf != NULL);
+ args->addr = get_netbuf(nconf, fshost, nmdp->nmd_nfs_port);
+ if (args->addr == NULL)
+ return (-ENOMEM);
+ *nconfp = nconf;
+ tinfo.tsdu = 0;
+
+ /* This shouldn't fail unless the zone is misconfigured */
+ if (stat(nconf->nc_device, &sb) < 0)
+ return (-ENOSR);
+
+ knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
+ if (!knconfp)
+ return (-ENOMEM);
+
+ knconfp->knc_semantics = nconf->nc_semantics;
+ knconfp->knc_protofmly = nconf->nc_protofmly;
+ knconfp->knc_proto = nconf->nc_proto;
+ knconfp->knc_rdev = sb.st_rdev;
+ args->flags |= NFSMNT_KNCONF;
+ args->knconf = knconfp;
+
+ /* make sure we don't overload the transport */
+ if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
+ args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
+ if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
+ args->rsize = tinfo.tsdu - NFS_RPC_HDR;
+ if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
+ args->wsize = tinfo.tsdu - NFS_RPC_HDR;
+ }
+
+ return (0);
+}
+
+static int
+append_opt(char *optstr, int len, char *k, char *v)
+{
+ int i;
+
+ for (i = 0; nmo_tab[i].nmo_lx_opt != NULL; i++) {
+ if (strcmp(k, nmo_tab[i].nmo_lx_opt) == 0) {
+ switch (nmo_tab[i].nmo_argtyp) {
+ case MOUNT_OPT_INVALID:
+ lx_unsupported("invalid NFS mount option: %s",
+ k);
+ return (-EINVAL);
+
+ case MOUNT_OPT_PASTHRU:
+ if (*optstr != '\0')
+ (void) strlcat(optstr, ",", len);
+ if (v == NULL) {
+ (void) strlcat(optstr, k, len);
+ } else {
+ (void) strlcat(optstr, k, len);
+ (void) strlcat(optstr, "=", len);
+ (void) strlcat(optstr, v, len);
+ }
+ break;
+
+ case MOUNT_OPT_IGNORE:
+ break;
+
+ case MOUNT_OPT_TOKEN:
+ if (*optstr != '\0')
+ (void) strlcat(optstr, ",", len);
+ (void) strlcat(optstr,
+ nmo_tab[i].nmo_il_opt, len);
+ break;
+
+ case MOUNT_OPT_HAS_ARG:
+ if (*optstr != '\0')
+ (void) strlcat(optstr, ",", len);
+ (void) strlcat(optstr,
+ nmo_tab[i].nmo_il_opt, len);
+ (void) strlcat(optstr, "=", len);
+ (void) strlcat(optstr, v, len);
+ break;
+ }
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+get_nfs_kv(char *vs, char **kp, char **vp)
+{
+ char *p;
+
+ p = strchr(vs, '=');
+ if (p == NULL) {
+ *kp = vs;
+ return (1);
+ }
+
+ *vp = p + 1;
+ *p = '\0';
+ *kp = vs;
+ return (0);
+}
+
+/*
+ * Convert the Linux-specific opt string into an Illumos opt string. We also
+ * fix up the special string (host:/path) to use the address that the
+ * user-level mount code has looked up. This overwrites both the srcp special
+ * string and the mntopts string.
+ *
+ * example input string, given 'nolock' as the only user-level option:
+ * nolock,vers=4,addr=127.0.0.1,clientaddr=0.0.0.0
+ *
+ * opt string (all one line) from a Centos 6 distro given 'nolock,vers=3' as
+ * the explicit options:
+ * nolock,addr=127.0.0.1,vers=3,proto=tcp,mountvers=3,mountproto=tcp,
+ * mountport=1892
+ *
+ * This is an example emitted by the Ubuntu 14.04 automounter for an explicit
+ * v3 mount:
+ * timeo=60,soft,intr,sloppy,addr=10.88.88.200,vers=3,proto=tcp,
+ * mountvers=3,mountproto=tcp,mountport=63484
+ */
+static int
+convert_nfs_arg_str(char *srcp, char *mntopts, nfs_mnt_data_t *nmdp)
+{
+ char *key, *val, *p;
+ char tmpbuf[MAX_MNTOPT_STR];
+ char *tbp = tmpbuf;
+ boolean_t no_sec = B_TRUE;
+ boolean_t no_addr = B_TRUE;
+
+ (void) strlcpy(tmpbuf, mntopts, sizeof (tmpbuf));
+ *mntopts = '\0';
+
+ while ((p = strsep(&tbp, ",")) != NULL) {
+ int tok;
+
+ tok = get_nfs_kv(p, &key, &val);
+
+ if (tok == 0) {
+ if (strcmp(key, "addr") == 0) {
+ /*
+ * The Linux user-level code looked up the
+ * address of the NFS server. We need to
+ * substitute that into the special string.
+ */
+ char *pp;
+ char spec[MAXPATHLEN + LX_NMD_MAXHOSTNAMELEN
+ + 1];
+
+ (void) strlcpy(spec, srcp, sizeof (spec));
+ pp = strchr(spec, ':');
+ if (pp == NULL)
+ return (-EINVAL);
+
+ pp++;
+ (void) snprintf(srcp,
+ MAXPATHLEN + LX_NMD_MAXHOSTNAMELEN + 1,
+ "%s:%s", val, pp);
+
+ no_addr = B_FALSE;
+ } else if (strcmp(key, "clientaddr") == 0) {
+ /*
+ * Ignore, this is an artifact of the
+ * user-level lx mount code.
+ */
+ /* EMPTY */
+ } else if (strcmp(key, "vers") == 0) {
+ /*
+ * This may be implicitly or explicitly passed.
+ * Check for the versions we want to support.
+ */
+ int r;
+ int v = atoi(val);
+
+ if (v != 3 && v != 4)
+ return (-EINVAL);
+
+ r = append_opt(mntopts, MAX_MNTOPT_STR,
+ key, val);
+ if (r != 0)
+ return (r);
+
+ } else if (strcmp(key, "sec") == 0) {
+ /*
+ * Linux supports: none, sys, krb5, krb5i, and
+ * krb5p. Of these, only none and sys overlap
+ * with our current support. Anything else is
+ * an error.
+ */
+ int r;
+
+ if (strcmp(val, "none") != 0 &&
+ strcmp(val, "sys") != 0)
+ return (-EINVAL);
+ r = append_opt(mntopts, MAX_MNTOPT_STR, key,
+ val);
+ if (r != 0)
+ return (r);
+ no_sec = B_FALSE;
+ } else if (strcmp(key, "nolock") == 0) {
+ int r;
+ nmdp->nmd_nolock_opt = 1;
+ r = append_opt(mntopts, MAX_MNTOPT_STR, key,
+ val);
+ if (r != 0)
+ return (r);
+ } else {
+ int r;
+
+ r = append_opt(mntopts, MAX_MNTOPT_STR,
+ key, val);
+ if (r != 0)
+ return (r);
+ }
+ } else {
+ int r;
+
+ r = append_opt(mntopts, MAX_MNTOPT_STR, key, NULL);
+ if (r != 0)
+ return (r);
+ }
+ }
+
+ if (no_addr) {
+ /*
+ * The Linux kernel requires an 'addr' option and will return
+ * EINVAL if one has not been provided. In particular, this
+ * behavior can be seen when the package which delivers NFS CLI
+ * support (e.g. nfs-common on Ubuntu, nfs-utils on Centos,
+ * etc.) is not installed. The generic mount command will not
+ * implicitly pass in the 'addr' option, the kernel will return
+ * EINVAL, and the mount will fail.
+ */
+ return (-EINVAL);
+ }
+
+ if (no_sec) {
+ /*
+ * XXX Temporarily work around missing DES auth by defaulting
+ * to sec=sys.
+ */
+ int r;
+
+ r = append_opt(mntopts, MAX_MNTOPT_STR, "sec", "sys");
+ if (r != 0)
+ return (r);
+ }
+
+ return (0);
+}
+
+int
+lx_nfs_mount(char *srcp, char *mntp, char *fst, int lx_flags, char *opts)
+{
+ int r;
+ int il_flags = 0;
+ nfs_mnt_data_t nmd, *nmdp = &nmd;
+ struct nfs_args *argp = NULL;
+ struct netconfig *nconf = NULL;
+ char *colonp;
+ char *path;
+ char *host;
+ char spec_buf[MAXPATHLEN + LX_NMD_MAXHOSTNAMELEN + 1];
+
+ bzero(&nmd, sizeof (nmd));
+ nmd.nmd_fstype = MNTTYPE_NFS;
+
+ /*
+ * This will modify the special string so that the hostname passed
+ * in will be replaced with the host address that the user-land code
+ * looked up. This also converts the opts string so that we'll be
+ * dealing with illumos options after this.
+ */
+ if ((r = convert_nfs_arg_str(srcp, opts, nmdp)) < 0) {
+ return (r);
+ }
+
+ if (strcmp(fst, "nfs4") == 0)
+ nmdp->nmd_nfsvers = NFS_V4;
+
+ /* Linux seems to always allow overlay mounts */
+ il_flags |= MS_OVERLAY;
+
+ /* Convert some Linux flags to Illumos flags. */
+ if (lx_flags & LX_MS_RDONLY)
+ il_flags |= MS_RDONLY;
+ if (lx_flags & LX_MS_NOSUID)
+ il_flags |= MS_NOSUID;
+ if (lx_flags & LX_MS_REMOUNT)
+ il_flags |= MS_REMOUNT;
+
+ /*
+ * Convert some Linux flags to Illumos option strings.
+ */
+ if (lx_flags & LX_MS_STRICTATIME) {
+ /*
+ * The "strictatime" mount option ensures that none of the
+ * weaker atime-related mode options are in effect.
+ */
+ lx_flags &= ~(LX_MS_RELATIME | LX_MS_NOATIME);
+ }
+ if ((lx_flags & LX_MS_NODEV) &&
+ ((r = i_add_option("nodev", opts, MAX_MNTOPT_STR)) != 0))
+ return (r);
+ if ((lx_flags & LX_MS_NOEXEC) &&
+ ((r = i_add_option("noexec", opts, MAX_MNTOPT_STR)) != 0))
+ return (r);
+ if ((lx_flags & LX_MS_NOATIME) &&
+ ((r = i_add_option("noatime", opts, MAX_MNTOPT_STR)) != 0))
+ return (r);
+
+ (void) strlcpy(spec_buf, srcp, sizeof (spec_buf));
+ colonp = strchr(spec_buf, ':');
+ if (colonp == NULL)
+ return (-EINVAL);
+
+ *colonp = '\0';
+ host = spec_buf;
+ path = colonp + 1;
+
+ argp = (struct nfs_args *)malloc(sizeof (*argp));
+ if (argp == NULL)
+ return (-ENOMEM);
+
+ (void) memset(argp, 0, sizeof (*argp));
+ (void) memset(&nmdp->nmd_nfs_sec, 0, sizeof (seconfig_t));
+ nmdp->nmd_sec_opt = 0;
+
+ /* returns a negative errno */
+ if ((r = set_args(&il_flags, argp, host, opts, nmdp)) != 0)
+ goto out;
+
+ if (nmdp->nmd_nfsvers == NFS_V4) {
+ /*
+ * In the case of version 4 there is no MOUNT program, thus no
+ * need for an RPC to get a file handle.
+ */
+ nmdp->nmd_fstype = MNTTYPE_NFS4;
+ argp->fh = strdup(path);
+ if (argp->fh == NULL) {
+ r = -ENOMEM;
+ goto out;
+ }
+ } else {
+ if ((r = get_fh(argp, host, path, nmdp)) < 0)
+ goto out;
+ }
+
+ if ((r = getaddr_nfs(argp, host, &nconf, nmdp)) < 0)
+ goto out;
+
+ if ((r = make_secure(argp, nmdp)) < 0)
+ goto out;
+
+ il_flags |= MS_DATA | MS_OPTIONSTR;
+
+ r = mount(srcp, mntp, il_flags, nmdp->nmd_fstype, argp, sizeof (*argp),
+ opts, MAX_MNTOPT_STR);
+ if (r != 0) {
+ r = -errno;
+ } else if (nmdp->nmd_nolock_opt == 0) {
+ (void) syscall(SYS_brand, B_START_NFS_LOCKD);
+ }
+
+out:
+ if (nconf != NULL)
+ freenetconfigent(nconf);
+ if (argp->fh)
+ free(argp->fh);
+ if (argp->pathconf)
+ free(argp->pathconf);
+ if (argp->knconf)
+ free(argp->knconf);
+ if (argp->addr) {
+ free(argp->addr->buf);
+ free(argp->addr);
+ }
+ if (argp->nfs_ext_u.nfs_extB.secdata)
+ free(argp->nfs_ext_u.nfs_extB.secdata);
+ if (argp->syncaddr) {
+ free(argp->syncaddr->buf);
+ free(argp->syncaddr);
+ }
+ if (argp->netname)
+ free(argp->netname);
+ free(argp);
+ if (nmdp->nmd_nfs_proto != NULL)
+ free(nmdp->nmd_nfs_proto);
+
+ return (r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/ptrace.c b/usr/src/lib/brand/lx/lx_brand/common/ptrace.c
new file mode 100644
index 0000000000..2c6f5041a1
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/ptrace.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_signal.h>
+#include <sys/lx_thread.h>
+#include <sys/lwp.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <procfs.h>
+#include <sys/frame.h>
+#include <strings.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/auxv.h>
+#include <thread.h>
+#include <pthread.h>
+#include <synch.h>
+#include <elf.h>
+#include <ieeefp.h>
+#include <assert.h>
+#include <libintl.h>
+#include <lx_syscall.h>
+
+/*
+ * Much of the Linux ptrace(2) emulation is performed in the kernel, and there
+ * is a block comment in "lx_ptrace.c" that describes the facility in some
+ * detail.
+ */
+
+
+void
+lx_ptrace_stop_if_option(int option, boolean_t child, ulong_t msg,
+ ucontext_t *ucp)
+{
+ /*
+ * We call into the kernel to see if we need to stop for specific
+ * ptrace(2) events.
+ */
+ lx_debug("lx_ptrace_stop_if_option(%d, %s, %lu, %p)", option,
+ child ? "TRUE [child]" : "FALSE [parent]", msg, ucp);
+ if (ucp == NULL) {
+ ucp = (ucontext_t *)lx_find_brand_uc();
+ lx_debug("\tucp = %p", ucp);
+ }
+ if (syscall(SYS_brand, B_PTRACE_STOP_FOR_OPT, option, child, msg,
+ ucp) != 0) {
+ if (errno != ESRCH) {
+ /*
+ * This should _only_ fail if we are not traced, or do
+ * not have this option set.
+ */
+ lx_err_fatal("B_PTRACE_STOP_FOR_OPT failed: %s",
+ strerror(errno));
+ }
+ }
+}
+
+/*
+ * Signal to the in-kernel ptrace(2) subsystem that the next native fork() or
+ * thr_create() is part of an emulated fork(2) or clone(2). If PTRACE_CLONE
+ * was passed to clone(2), inherit_flag should be B_TRUE.
+ */
+void
+lx_ptrace_clone_begin(int option, boolean_t inherit_flag, int flags)
+{
+ lx_debug("lx_ptrace_clone_begin(%d, %sPTRACE_CLONE)", option,
+ inherit_flag ? "" : "!");
+ if (syscall(SYS_brand, B_PTRACE_CLONE_BEGIN, option,
+ inherit_flag, flags) != 0) {
+ lx_err_fatal("B_PTRACE_CLONE_BEGIN failed: %s",
+ strerror(errno));
+ }
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/sendfile.c b/usr/src/lib/brand/lx/lx_brand/common/sendfile.c
new file mode 100644
index 0000000000..c09e8c51dc
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/sendfile.c
@@ -0,0 +1,143 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * lx_sendfile() and lx_sendfile64() are primarily branded versions of the
+ * library calls available in the Solaris libsendfile (see sendfile(3EXT)).
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/sendfile.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+#if defined(_ILP32)
+long
+lx_sendfile(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ sysret_t rval;
+ off_t off = 0;
+ off_t *offp = (off_t *)p3;
+ int error;
+ struct sendfilevec sfv;
+ size_t xferred = 0;
+ size_t sz = (size_t)p4;
+
+ if (offp == NULL) {
+ /* If no offp, we must use the current offset */
+ if ((off = lseek((int)p2, 0, SEEK_CUR)) == -1)
+ return (-errno);
+ } else {
+ if (sz > 0 && uucopy(offp, &off, sizeof (off)) != 0)
+ return (-errno);
+ if (off < 0)
+ return (-EINVAL);
+ }
+
+ sfv.sfv_fd = p2;
+ sfv.sfv_flag = 0;
+ sfv.sfv_off = off;
+ sfv.sfv_len = sz;
+ error = __systemcall(&rval, SYS_sendfilev, SENDFILEV, p1, &sfv,
+ 1, &xferred);
+
+ /* Suppress errors if we were able to write any data at all. */
+ if (xferred > 0) {
+ error = 0;
+ }
+
+ if (error == 0) {
+ off += xferred;
+ if (offp == NULL) {
+ /* If no offp, we must adjust current offset */
+ if (lseek((int)p2, off, SEEK_SET) == -1)
+ return (-errno);
+ } else {
+ if (uucopy(&off, offp, sizeof (off)) != 0) {
+ return (-EFAULT);
+ }
+ }
+ }
+
+ return (error ? -error : xferred);
+}
+#endif
+
+long
+lx_sendfile64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ sysret_t rval;
+ off64_t off = 0;
+ off64_t *offp = (off64_t *)p3;
+ size_t sz = (size_t)p4;
+ int error;
+ struct sendfilevec64 sfv;
+ size_t xferred;
+
+ if (offp == NULL) {
+ /* If no offp, we must use the current offset */
+ if ((off = lseek((int)p2, 0, SEEK_CUR)) == -1)
+ return (-errno);
+ } else {
+ if (sz > 0 && uucopy(offp, &off, sizeof (off)) != 0)
+ return (-errno);
+ if (off < 0)
+ return (-EINVAL);
+ }
+
+ sfv.sfv_fd = p2;
+ sfv.sfv_flag = 0;
+ sfv.sfv_off = off;
+ sfv.sfv_len = sz;
+ xferred = 0;
+ error = __systemcall(&rval, SYS_sendfilev, SENDFILEV64, p1, &sfv,
+ 1, &xferred);
+
+ /* Suppress errors if we were able to write any data at all. */
+ if (xferred > 0) {
+ error = 0;
+ }
+
+ if (error == 0) {
+ off += xferred;
+ if (offp == NULL) {
+ /* If no offp, we must adjust current offset */
+ if (lseek((int)p2, off, SEEK_SET) == -1)
+ return (-errno);
+ } else {
+ if (uucopy(&off, offp, sizeof (off)) != 0) {
+ return (-EFAULT);
+ }
+ }
+ }
+
+ return (error ? -error : xferred);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/signal.c b/usr/src/lib/brand/lx/lx_brand/common/signal.c
new file mode 100644
index 0000000000..45de7615bc
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c
@@ -0,0 +1,2378 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/segments.h>
+#include <sys/lx_types.h>
+#include <sys/lx_brand.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_poll.h>
+#include <sys/lx_signal.h>
+#include <sys/lx_sigstack.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_thread.h>
+#include <sys/syscall.h>
+#include <lx_provider_impl.h>
+#include <sys/stack.h>
+#include <assert.h>
+#include <errno.h>
+#include <poll.h>
+#include <rctl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <thread.h>
+#include <ucontext.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <libintl.h>
+#include <ieeefp.h>
+#include <sys/signalfd.h>
+
+#if defined(_ILP32)
+extern int pselect_large_fdset(int nfds, fd_set *in0, fd_set *out0, fd_set *ex0,
+ const timespec_t *tsp, const sigset_t *sp);
+#endif
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/*
+ * Delivering signals to a Linux process is complicated by differences in
+ * signal numbering, stack structure and contents, and the action taken when a
+ * signal handler exits. In addition, many signal-related structures, such as
+ * sigset_ts, vary between Illumos and Linux.
+ *
+ * To support user-level signal handlers, the brand uses a double layer of
+ * indirection to process and deliver signals to branded threads.
+ *
+ * When a Linux process sends a signal using the kill(2) system call, we must
+ * translate the signal into the Illumos equivalent before handing control off
+ * to the standard signalling mechanism. When a signal is delivered to a Linux
+ * process, we translate the signal number from Illumos to back to Linux.
+ * Translating signals both at generation and delivery time ensures both that
+ * Illumos signals are sent properly to Linux applications and that signals'
+ * default behavior works as expected.
+ *
+ * In a normal Illumos process, signal delivery is interposed on for any thread
+ * registering a signal handler by libc. Libc needs to do various bits of magic
+ * to provide thread-safe critical regions, so it registers its own handler,
+ * named sigacthandler(), using the sigaction(2) system call. When a signal is
+ * received, sigacthandler() is called, and after some processing, libc turns
+ * around and calls the user's signal handler via a routine named
+ * call_user_handler().
+ *
+ * Adding a Linux branded thread to the mix complicates things somewhat.
+ *
+ * First, when a thread receives a signal, it may either be running in an
+ * emulated Linux context or a native illumos context. In either case, the
+ * in-kernel brand module is responsible for preserving the register state
+ * from the interrupted context, regardless of whether emulated or native
+ * software was running at the time. The kernel is also responsible for
+ * ensuring that the illumos native sigacthandler() is called with register
+ * values appropriate for native code. Of particular note is the %gs segment
+ * selector for 32-bit code, and the %fsbase segment base register for 64-bit
+ * code; these are used by libc to locate per-thread data structures.
+ *
+ * Second, the signal number translation referenced above must take place.
+ * Finally, when we hand control to the Linux signal handler we must do so
+ * on the brand stack, and with registers configured appropriately for the
+ * Linux application.
+ *
+ * This need to translate signal numbers (and manipulate the signal handling
+ * context) means that with standard Illumos libc, following a signal from
+ * generation to delivery looks something like:
+ *
+ * kernel ->
+ * sigacthandler() ->
+ * call_user_handler() ->
+ * user signal handler
+ *
+ * but for the brand's Linux threads, this would look like:
+ *
+ * kernel ->
+ * sigacthandler() ->
+ * call_user_handler() ->
+ * lx_call_user_handler() ->
+ * lx_sigdeliver() ->
+ * syscall(B_JUMP_TO_LINUX, ...) ->
+ * Linux user signal handler
+ *
+ * The new addtions are:
+ *
+ * lx_call_user_handler
+ * ====================
+ * This routine is responsible for translating Illumos signal numbers to
+ * their Linux equivalents, building a Linux signal stack based on the
+ * information Illumos has provided, and passing the stack to the
+ * registered Linux signal handler. It is, in effect, the Linux thread
+ * equivalent to libc's call_user_handler().
+ *
+ * lx_sigdeliver
+ * =============
+ *
+ * Note that none of this interposition is necessary unless a Linux thread
+ * registers a user signal handler, as the default action for all signals is the
+ * same between Illumos and Linux save for one signal, SIGPWR. For this reason,
+ * the brand ALWAYS installs its own internal signal handler for SIGPWR that
+ * translates the action to the Linux default, to terminate the process.
+ * (Illumos' default action is to ignore SIGPWR.)
+ *
+ * A notable behavior of lx_sigdeliver is that it must replace the stack
+ * pointer in the context that will be handed to the Linux signal handler.
+ * There is at least one application (mono) which inspects the SP in the
+ * context it receives and which fails when the SP is not within the thread's
+ * stack range. There is not much else within the context that a signal
+ * handler could depend on, so we only ensure that the SP is from the Linux
+ * stack and not the alternate stack. lx_sigdeliver will restore the correct
+ * SP when setcontext returns into this function as part of returning from
+ * the signal handler.
+ *
+ * It is also important to note that when signals are not translated, the brand
+ * relies upon code interposing upon the wait(2) system call to translate
+ * signals to their proper values for any Linux threads retrieving the status
+ * of others. So while the Illumos signal number for a particular signal is set
+ * in a process' data structures (and would be returned as the result of say,
+ * WTERMSIG()), the brand's interposiiton upon wait(2) is responsible for
+ * translating the value WTERMSIG() would return from a Illumos signal number
+ * to the appropriate Linux value.
+ *
+ * lx_call_user_handler() calls lx_sigdeliver() with a helper function
+ * (typically lx_build_signal_frame) which builds a stack frame for the 32-bit
+ * Linux signal handler, or populates a local (on the stack) structure for the
+ * 64-bit Linux signal handler. The stack at that time looks like this:
+ *
+ * =========================================================
+ * | | lx_sigdeliver_frame_t -- includes LX_SIGRT_MAGIC and |
+ * | | a return context for the eventual sigreturn(2) call |
+ * | =========================================================
+ * | | Linux signal frame (32-bit) or local data |
+ * V | (64-bit) built by stack_builder() |
+ * =========================================================
+ *
+ * The process of returning to an interrupted thread of execution from a user
+ * signal handler is entirely different between Illumos and Linux. While
+ * Illumos generally expects to set the context to the interrupted one on a
+ * normal return from a signal handler, in the normal case Linux instead calls
+ * code that calls a specific Linux system call, rt_sigreturn(2) (or it also
+ * can call sigreturn(2) in 32-bit code). Thus when a Linux signal handler
+ * completes execution, instead of returning through what would in libc be a
+ * call to setcontext(2), the rt_sigreturn(2) Linux system call is responsible
+ * for accomplishing much the same thing. It's for this reason that the stack
+ * frame we build has the lx_(rt_)sigreturn_tramp code on the top of the
+ * stack. The code looks like this:
+ *
+ * 32-bit 64-bit
+ * -------------------------------- -----------------------------
+ * mov LX_SYS_rt_sigreturn, %eax movq LX_SYS_rt_sigreturn, %rax
+ * int $0x80 syscall
+ *
+ * We also use these same functions (lx_rt_sigreturn_tramp or
+ * lx_sigreturn_tramp) to actually return from the signal handler.
+ *
+ * (Note that this trampoline code actually lives in a proper executable segment
+ * and not on the stack, but gdb checks for the exact code sequence of the
+ * trampoline code on the stack to determine whether it is in a signal stack
+ * frame or not. Really.)
+ *
+ * When the 32-bit Linux user signal handler is eventually called, the brand
+ * stack frame looks like this (in the case of a "modern" signal stack; see
+ * the lx_sigstack structure definition):
+ *
+ * =========================================================
+ * | | lx_sigdeliver_frame_t |
+ * | =========================================================
+ * | | Trampoline code (marker for gdb, not really executed) |
+ * | =========================================================
+ * | | Linux struct _fpstate |
+ * | =========================================================
+ * V | Linux ucontext_t | <--+
+ * ========================================================= |
+ * | Linux siginfo_t | <--|-----+
+ * ========================================================= | |
+ * | Pointer to Linux ucontext_t (or NULL) (sigaction arg2)| ---+ |
+ * ========================================================= |
+ * | Pointer to Linux siginfo_t (or NULL) (sigaction arg1)| ---------+
+ * =========================================================
+ * | Linux signal number (sigaction arg0)|
+ * =========================================================
+ * | Pointer to signal return code (trampoline code) |
+ * =========================================================
+ *
+ * The 64-bit stack-local data looks like this:
+ *
+ * =========================================================
+ * | | lx_sigdeliver_frame_t |
+ * | =========================================================
+ * | | Trampoline code (marker for gdb, not really executed) |
+ * | =========================================================
+ * | | Linux struct _fpstate |
+ * | =========================================================
+ * V | Linux ucontext_t | %rdx arg2
+ * =========================================================
+ * | Linux siginfo_t | %rsi arg1
+ * =========================================================
+ * | Pointer to signal return code (trampoline code) |
+ * =========================================================
+ *
+ * As usual in 64-bit code, %rdi is arg0 which is the signal number.
+ *
+ * The *sigreturn(2) family of emulated system call handlers locates the
+ * "lx_sigdeliver_frame_t" struct on the Linux stack as part of processing
+ * the system call. This object contains a guard value (LX_SIGRT_MAGIC) to
+ * detect stack smashing or an incorrect stack pointer. It also contains a
+ * "return" context, which we use to get back to the "lx_sigdeliver()" frame
+ * on the native stack that originally dispatched to the Linux signal
+ * handler. The lx_sigdeliver() function is then able to return to the
+ * native libc signal handler in the usual way. This results in a further
+ * setcontext() back to whatever was running when we took the signal.
+ *
+ * There are some edge cases where the "return" context cannot be located
+ * by inspection of the Linux stack; e.g. if the guard value has been
+ * corrupted, or the emulated program has relocated parts of the signal
+ * delivery stack frame. If this case is detected, a fallback mechanism is
+ * used to attempt to find the return context. A chain of "lx_sigbackup_t"
+ * objects is maintained in signal interposer call frames, with the current
+ * head stored in the thread-specific "lx_tsd_t". This mechanism is
+ * similar in principle to the "lwp_oldcontext" member of the "klwp_t" used
+ * by the native signal handling infrastructure. This backup chain is used
+ * by the sigreturn(2) family of emulated system calls in the event that
+ * the Linux stack did not correctly reference a return context.
+ */
+
+typedef struct lx_sigdeliver_frame {
+ uintptr_t lxsdf_magic;
+ ucontext_t *lxsdf_retucp;
+ ucontext_t *lxsdf_sigucp;
+ lx_sigbackup_t *lxsdf_sigbackup;
+} lx_sigdeliver_frame_t;
+
+struct lx_oldsigstack {
+ void (*retaddr)(); /* address of real lx_sigreturn code */
+ int sig; /* signal number */
+ lx_sigcontext_t sigc; /* saved user context */
+ lx_fpstate_t fpstate; /* saved FP state */
+ int sig_extra; /* signal mask for signals [32 .. NSIG - 1] */
+ char trampoline[8]; /* code for trampoline to lx_sigreturn() */
+};
+
+/*
+ * The lx_sighandlers structure needs to be a global due to the semantics of
+ * clone().
+ *
+ * If CLONE_SIGHAND is set, the calling process and child share signal
+ * handlers, and if either calls sigaction(2) it should change the behavior
+ * in the other thread. Each thread does, however, have its own signal mask
+ * and set of pending signals.
+ *
+ * If CLONE_SIGHAND is not set, the child process should inherit a copy of
+ * the signal handlers at the time of the clone() but later calls to
+ * sigaction(2) should only affect the individual thread calling it.
+ *
+ * This maps perfectly to a thr_create(3C) thread semantic in the first
+ * case and a fork(2)-type semantic in the second case. By making
+ * lx_sighandlers global, we automatically get the correct behavior.
+ */
+static lx_sighandlers_t lx_sighandlers;
+
+static void lx_sigdeliver(int, siginfo_t *, ucontext_t *, size_t, void (*)(),
+ void (*)(), struct lx_sigaction *);
+
+/*
+ * stol_stack() and ltos_stack() convert between Illumos and Linux stack_t
+ * structures.
+ *
+ * These routines are needed because although the two structures have the same
+ * contents, their contents are declared in a different order, so the content
+ * of the structures cannot be copied with a simple bcopy().
+ */
+static void
+stol_stack(stack_t *fr, lx_stack_t *to)
+{
+ to->ss_sp = fr->ss_sp;
+ to->ss_flags = fr->ss_flags;
+ to->ss_size = fr->ss_size;
+}
+
+static void
+ltos_stack(lx_stack_t *fr, stack_t *to)
+{
+ to->ss_sp = fr->ss_sp;
+ to->ss_flags = fr->ss_flags;
+ to->ss_size = fr->ss_size;
+}
+
+static int
+ltos_sigset(lx_sigset_t *lx_sigsetp, sigset_t *s_sigsetp)
+{
+ lx_sigset_t l;
+ int lx_sig, sig;
+
+ if (uucopy(lx_sigsetp, &l, sizeof (lx_sigset_t)) != 0)
+ return (-errno);
+
+ (void) sigemptyset(s_sigsetp);
+
+ for (lx_sig = 1; lx_sig <= LX_NSIG; lx_sig++) {
+ if (lx_sigismember(&l, lx_sig) &&
+ ((sig = ltos_signo[lx_sig]) > 0))
+ (void) sigaddset(s_sigsetp, sig);
+ }
+
+ return (0);
+}
+
+static int
+stol_sigset(sigset_t *s_sigsetp, lx_sigset_t *lx_sigsetp)
+{
+ lx_sigset_t l;
+ int sig, lx_sig;
+
+ bzero(&l, sizeof (lx_sigset_t));
+
+ for (sig = 1; sig < NSIG; sig++) {
+ if (sigismember(s_sigsetp, sig) &&
+ ((lx_sig = stol_signo[sig]) > 0))
+ lx_sigaddset(&l, lx_sig);
+ }
+
+ return ((uucopy(&l, lx_sigsetp, sizeof (lx_sigset_t)) != 0)
+ ? -errno : 0);
+}
+
+#if defined(_ILP32)
+static int
+ltos_osigset(lx_osigset_t *lx_osigsetp, sigset_t *s_sigsetp)
+{
+ lx_osigset_t lo;
+ int lx_sig, sig;
+
+ if (uucopy(lx_osigsetp, &lo, sizeof (lx_osigset_t)) != 0)
+ return (-errno);
+
+ (void) sigemptyset(s_sigsetp);
+
+ for (lx_sig = 1; lx_sig <= OSIGSET_NBITS; lx_sig++)
+ if ((lo & OSIGSET_BITSET(lx_sig)) &&
+ ((sig = ltos_signo[lx_sig]) > 0))
+ (void) sigaddset(s_sigsetp, sig);
+
+ return (0);
+}
+
+static int
+stol_osigset(sigset_t *s_sigsetp, lx_osigset_t *lx_osigsetp)
+{
+ lx_osigset_t lo = 0;
+ int lx_sig, sig;
+
+ /*
+ * Note that an lx_osigset_t can only represent the signals from
+ * [1 .. OSIGSET_NBITS], so even though a signal may be present in the
+ * Illumos sigset_t, it may not be representable as a bit in the
+ * lx_osigset_t.
+ */
+ for (sig = 1; sig < NSIG; sig++)
+ if (sigismember(s_sigsetp, sig) &&
+ ((lx_sig = stol_signo[sig]) > 0) &&
+ (lx_sig <= OSIGSET_NBITS))
+ lo |= OSIGSET_BITSET(lx_sig);
+
+ return ((uucopy(&lo, lx_osigsetp, sizeof (lx_osigset_t)) != 0)
+ ? -errno : 0);
+}
+#endif
+
+static int
+ltos_sigcode(int si_code)
+{
+ switch (si_code) {
+ case LX_SI_USER:
+ return (SI_USER);
+ case LX_SI_TKILL:
+ return (SI_LWP);
+ case LX_SI_QUEUE:
+ return (SI_QUEUE);
+ case LX_SI_TIMER:
+ return (SI_TIMER);
+ case LX_SI_ASYNCIO:
+ return (SI_ASYNCIO);
+ case LX_SI_MESGQ:
+ return (SI_MESGQ);
+ default:
+ return (LX_SI_CODE_NOT_EXIST);
+ }
+}
+
+int
+stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop)
+{
+ int ret = 0;
+ lx_siginfo_t lx_siginfo;
+
+ bzero(&lx_siginfo, sizeof (*lx_siginfop));
+
+ if ((lx_siginfo.lsi_signo = stol_signo[siginfop->si_signo]) <= 0) {
+ /*
+ * Depending on the caller we may still need to get a usable
+ * converted siginfo struct.
+ */
+ lx_siginfo.lsi_signo = LX_SIGKILL;
+ errno = EINVAL;
+ ret = -1;
+ }
+
+ lx_siginfo.lsi_code = lx_stol_sigcode(siginfop->si_code);
+ lx_siginfo.lsi_errno = siginfop->si_errno;
+
+ switch (lx_siginfo.lsi_signo) {
+ /*
+ * Semantics ARE defined for SIGKILL, but since
+ * we can't catch it, we can't translate it. :-(
+ */
+ case LX_SIGPOLL:
+ lx_siginfo.lsi_band = siginfop->si_band;
+ lx_siginfo.lsi_fd = siginfop->si_fd;
+ break;
+
+ case LX_SIGCHLD:
+ lx_siginfo.lsi_pid = siginfop->si_pid;
+ if (siginfop->si_code <= 0 || siginfop->si_code ==
+ CLD_EXITED) {
+ lx_siginfo.lsi_status = siginfop->si_status;
+ } else {
+ lx_siginfo.lsi_status = lx_stol_status(
+ siginfop->si_status, -1);
+ }
+ lx_siginfo.lsi_utime = siginfop->si_utime;
+ lx_siginfo.lsi_stime = siginfop->si_stime;
+ break;
+
+ case LX_SIGILL:
+ case LX_SIGBUS:
+ case LX_SIGFPE:
+ case LX_SIGSEGV:
+ lx_siginfo.lsi_addr = siginfop->si_addr;
+ break;
+
+ default:
+ lx_siginfo.lsi_pid = siginfop->si_pid;
+ lx_siginfo.lsi_uid =
+ LX_UID32_TO_UID16(siginfop->si_uid);
+ lx_siginfo.lsi_value = siginfop->si_value;
+ break;
+ }
+
+ if (uucopy(&lx_siginfo, lx_siginfop, sizeof (lx_siginfo_t)) != 0)
+ return (-errno);
+ return ((ret != 0) ? -errno : 0);
+}
+
+static void
+stol_fpstate(fpregset_t *fpr, lx_fpstate_t *lfpr)
+{
+ size_t copy_len;
+
+#if defined(_LP64)
+ /*
+ * The 64-bit Illumos struct fpregset_t and lx_fpstate_t are identical
+ * so just bcopy() those entries (see usr/src/uts/intel/sys/regset.h
+ * for __amd64's struct fpu).
+ */
+ copy_len = sizeof (fpr->fp_reg_set.fpchip_state);
+ bcopy(fpr, lfpr, copy_len);
+
+#else /* is _ILP32 */
+ struct _fpstate *fpsp = (struct _fpstate *)fpr;
+
+ /*
+ * The Illumos struct _fpstate and lx_fpstate_t are identical from the
+ * beginning of the structure to the lx_fpstate_t "magic" field, so
+ * just bcopy() those entries.
+ */
+ copy_len = (size_t)&(((lx_fpstate_t *)0)->magic);
+ bcopy(fpsp, lfpr, copy_len);
+
+ /*
+ * These fields are all only significant for the first 16 bits.
+ */
+ lfpr->cw &= 0xffff; /* x87 control word */
+ lfpr->tag &= 0xffff; /* x87 tag word */
+ lfpr->cssel &= 0xffff; /* cs selector */
+ lfpr->datasel &= 0xffff; /* ds selector */
+
+ /*
+ * Linux wants the x87 status word field to contain the value of the
+ * x87 saved exception status word.
+ */
+ lfpr->sw = lfpr->status & 0xffff; /* x87 status word */
+
+ lfpr->mxcsr = fpsp->mxcsr;
+
+ if (fpsp->mxcsr != 0) {
+ /*
+ * Linux uses the "magic" field to denote whether the XMM
+ * registers contain legal data or not. Since we can't get to
+ * %cr4 from userland to check the status of the OSFXSR bit,
+ * check the mxcsr field to see if it's 0, which it should
+ * never be on a system with the OXFXSR bit enabled.
+ */
+ lfpr->magic = LX_X86_FXSR_MAGIC;
+ bcopy(fpsp->xmm, lfpr->_xmm, sizeof (lfpr->_xmm));
+ } else {
+ lfpr->magic = LX_X86_FXSR_NONE;
+ }
+#endif
+}
+
+static void
+ltos_fpstate(lx_fpstate_t *lfpr, fpregset_t *fpr)
+{
+ size_t copy_len;
+
+#if defined(_LP64)
+ /*
+ * The 64-bit Illumos struct fpregset_t and lx_fpstate_t are identical
+ * so just bcopy() those entries (see usr/src/uts/intel/sys/regset.h
+ * for __amd64's struct fpu).
+ */
+ copy_len = sizeof (fpr->fp_reg_set.fpchip_state);
+ bcopy(lfpr, fpr, copy_len);
+
+#else /* is _ILP32 */
+ struct _fpstate *fpsp = (struct _fpstate *)fpr;
+
+ /*
+ * The lx_fpstate_t and Illumos struct _fpstate are identical from the
+ * beginning of the structure to the struct _fpstate "mxcsr" field, so
+ * just bcopy() those entries.
+ *
+ * Note that we do NOT have to propogate changes the user may have made
+ * to the "status" word back to the "sw" word, unlike the way we have
+ * to deal with processing the ESP and UESP register values on return
+ * from a signal handler.
+ */
+ copy_len = (size_t)&(((struct _fpstate *)0)->mxcsr);
+ bcopy(lfpr, fpsp, copy_len);
+
+ /*
+ * These fields are all only significant for the first 16 bits.
+ */
+ fpsp->cw &= 0xffff; /* x87 control word */
+ fpsp->sw &= 0xffff; /* x87 status word */
+ fpsp->tag &= 0xffff; /* x87 tag word */
+ fpsp->cssel &= 0xffff; /* cs selector */
+ fpsp->datasel &= 0xffff; /* ds selector */
+ fpsp->status &= 0xffff; /* saved status */
+
+ fpsp->mxcsr = lfpr->mxcsr;
+
+ if (lfpr->magic == LX_X86_FXSR_MAGIC)
+ bcopy(lfpr->_xmm, fpsp->xmm, sizeof (fpsp->xmm));
+#endif
+}
+
+/*
+ * We do not use the system sigaltstack() infrastructure as that would conflict
+ * with our handling of both system call emulation and native signals on the
+ * native stack. Instead, we track the Linux stack structure in our
+ * thread-specific data. This function is modeled on the behaviour of the
+ * native sigaltstack system call handler.
+ */
+long
+lx_sigaltstack(uintptr_t ssp, uintptr_t oss)
+{
+ lx_tsd_t *lxtsd = lx_get_tsd();
+ lx_stack_t ss;
+
+ if (ssp != NULL) {
+ if (lxtsd->lxtsd_sigaltstack.ss_flags & LX_SS_ONSTACK) {
+ /*
+ * If we are currently using the installed alternate
+ * stack for signal handling, the user may not modify
+ * the stack for this thread.
+ */
+ return (-EPERM);
+ }
+
+ if (uucopy((void *)ssp, &ss, sizeof (ss)) != 0) {
+ return (-EFAULT);
+ }
+
+ if (ss.ss_flags & ~LX_SS_DISABLE) {
+ /*
+ * The user may not specify a value for flags other
+ * than 0 or SS_DISABLE.
+ */
+ return (-EINVAL);
+ }
+
+ if (!(ss.ss_flags & LX_SS_DISABLE) && ss.ss_size <
+ LX_MINSIGSTKSZ) {
+ return (-ENOMEM);
+ }
+
+ if ((ss.ss_flags & LX_SS_DISABLE) != 0) {
+ ss.ss_sp = NULL;
+ ss.ss_size = 0;
+ }
+ }
+
+ if (oss != NULL) {
+ /*
+ * User provided old and new stack_t pointers may point to
+ * the same location. Copy out before we modify.
+ */
+ if (uucopy(&lxtsd->lxtsd_sigaltstack, (void *)oss,
+ sizeof (lxtsd->lxtsd_sigaltstack)) != 0) {
+ return (-EFAULT);
+ }
+ }
+
+ if (ssp != NULL) {
+ lxtsd->lxtsd_sigaltstack = ss;
+ }
+
+ return (0);
+}
+
+#if defined(_ILP32)
+/*
+ * The following routines are needed because sigset_ts and siginfo_ts are
+ * different in format between Linux and Illumos.
+ *
+ * Note that there are two different lx_sigset structures, lx_sigset_ts and
+ * lx_osigset_ts:
+ *
+ * + An lx_sigset_t is the equivalent of a Illumos sigset_t and supports
+ * more than 32 signals.
+ *
+ * + An lx_osigset_t is simply a uint32_t, so it by definition only supports
+ * 32 signals.
+ *
+ * When there are two versions of a routine, one prefixed with lx_rt_ and
+ * one prefixed with lx_ alone, in GENERAL the lx_rt_ routines deal with
+ * lx_sigset_ts while the lx_ routines deal with lx_osigset_ts. Unfortunately,
+ * this is not always the case (e.g. lx_sigreturn() vs. lx_rt_sigreturn())
+ */
+long
+lx_sigpending(uintptr_t sigpend)
+{
+ sigset_t sigpendset;
+
+ if (sigpending(&sigpendset) != 0)
+ return (-errno);
+
+ return (stol_osigset(&sigpendset, (lx_osigset_t *)sigpend));
+}
+#endif
+
+long
+lx_rt_sigpending(uintptr_t sigpend, uintptr_t setsize)
+{
+ sigset_t sigpendset;
+
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ if (sigpending(&sigpendset) != 0)
+ return (-errno);
+
+ return (stol_sigset(&sigpendset, (lx_sigset_t *)sigpend));
+}
+
+/*
+ * Create a common routine to encapsulate all of the sigprocmask code,
+ * as the only difference between lx_sigprocmask() and lx_rt_sigprocmask()
+ * is the usage of lx_osigset_ts vs. lx_sigset_ts, as toggled in the code by
+ * the setting of the "sigset_type" flag.
+ */
+static int
+lx_sigprocmask_common(uintptr_t how, uintptr_t l_setp, uintptr_t l_osetp,
+ uintptr_t sigset_type)
+{
+ int err = 0;
+ sigset_t set, oset;
+ sigset_t *s_setp = NULL;
+ sigset_t *s_osetp;
+
+ if (l_setp) {
+ switch (how) {
+ case LX_SIG_BLOCK:
+ how = SIG_BLOCK;
+ break;
+
+ case LX_SIG_UNBLOCK:
+ how = SIG_UNBLOCK;
+ break;
+
+ case LX_SIG_SETMASK:
+ how = SIG_SETMASK;
+ break;
+
+ default:
+ return (-EINVAL);
+ }
+
+ s_setp = &set;
+
+ /* Only 32-bit code passes other than USE_SIGSET */
+ if (sigset_type == USE_SIGSET)
+ err = ltos_sigset((lx_sigset_t *)l_setp, s_setp);
+#if defined(_ILP32)
+ else
+ err = ltos_osigset((lx_osigset_t *)l_setp, s_setp);
+#endif
+
+ if (err != 0)
+ return (err);
+
+ }
+
+ s_osetp = (l_osetp ? &oset : NULL);
+
+ /*
+ * In a multithreaded environment, a call to sigprocmask(2) should
+ * only affect the current thread's signal mask so we don't need to
+ * explicitly call thr_sigsetmask(3C) here.
+ */
+ if (sigprocmask(how, s_setp, s_osetp) != 0)
+ return (-errno);
+
+ if (l_osetp) {
+ if (sigset_type == USE_SIGSET)
+ err = stol_sigset(s_osetp, (lx_sigset_t *)l_osetp);
+#if defined(_ILP32)
+ else
+ err = stol_osigset(s_osetp, (lx_osigset_t *)l_osetp);
+#endif
+
+ if (err != 0) {
+ /*
+ * Encountered a fault while writing to the old signal
+ * mask buffer, so unwind the signal mask change made
+ * above.
+ */
+ (void) sigprocmask(how, s_osetp, (sigset_t *)NULL);
+ return (err);
+ }
+ }
+
+ return (0);
+}
+
+#if defined(_ILP32)
+long
+lx_sigprocmask(uintptr_t how, uintptr_t setp, uintptr_t osetp)
+{
+ return (lx_sigprocmask_common(how, setp, osetp, USE_OSIGSET));
+}
+#endif
+
+long
+lx_rt_sigprocmask(uintptr_t how, uintptr_t setp, uintptr_t osetp,
+ uintptr_t setsize)
+{
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ return (lx_sigprocmask_common(how, setp, osetp, USE_SIGSET));
+}
+
+#if defined(_ILP32)
+long
+lx_sigsuspend(uintptr_t set)
+{
+ sigset_t s_set;
+
+ if (ltos_osigset((lx_osigset_t *)set, &s_set) != 0)
+ return (-errno);
+
+ return ((sigsuspend(&s_set) == -1) ? -errno : 0);
+}
+#endif
+
+long
+lx_rt_sigsuspend(uintptr_t set, uintptr_t setsize)
+{
+ sigset_t s_set;
+
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ if (ltos_sigset((lx_sigset_t *)set, &s_set) != 0)
+ return (-errno);
+
+ return ((sigsuspend(&s_set) == -1) ? -errno : 0);
+}
+
+long
+lx_rt_sigwaitinfo(uintptr_t set, uintptr_t sinfo, uintptr_t setsize)
+{
+ sigset_t s_set;
+ siginfo_t s_sinfo, *s_sinfop;
+ int rc;
+
+ lx_sigset_t *setp = (lx_sigset_t *)set;
+ lx_siginfo_t *sinfop = (lx_siginfo_t *)sinfo;
+
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ if (ltos_sigset(setp, &s_set) != 0)
+ return (-errno);
+
+ s_sinfop = (sinfop == NULL) ? NULL : &s_sinfo;
+
+ if ((rc = sigwaitinfo(&s_set, s_sinfop)) == -1)
+ return (-errno);
+
+ if (s_sinfop == NULL)
+ return (stol_signo[rc]);
+
+ return ((stol_siginfo(s_sinfop, sinfop) != 0)
+ ? -errno : stol_signo[rc]);
+}
+
+long
+lx_rt_sigtimedwait(uintptr_t set, uintptr_t sinfo, uintptr_t toutp,
+ uintptr_t setsize)
+{
+ sigset_t s_set;
+ siginfo_t s_sinfo, *s_sinfop;
+ int rc;
+
+ lx_sigset_t *setp = (lx_sigset_t *)set;
+ lx_siginfo_t *sinfop = (lx_siginfo_t *)sinfo;
+
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ if (ltos_sigset(setp, &s_set) != 0)
+ return (-errno);
+
+ s_sinfop = (sinfop == NULL) ? NULL : &s_sinfo;
+
+ /*
+ * "If timeout is the NULL pointer, the behavior is unspecified."
+ * Match what LTP expects.
+ */
+ if ((rc = sigtimedwait(&s_set, s_sinfop,
+ (struct timespec *)toutp)) == -1)
+ return (toutp == NULL ? -EINTR : -errno);
+
+ if (s_sinfop == NULL)
+ return (stol_signo[rc]);
+
+ return ((stol_siginfo(s_sinfop, sinfop) != 0)
+ ? -errno : stol_signo[rc]);
+}
+
+static void
+lx_sigreturn_find_native_context(const char *caller, ucontext_t **sigucp,
+ ucontext_t **retucp, uintptr_t sp)
+{
+ lx_tsd_t *lxtsd = lx_get_tsd();
+ lx_sigdeliver_frame_t *lxsdfp = (lx_sigdeliver_frame_t *)sp;
+ lx_sigdeliver_frame_t lxsdf;
+ boolean_t copy_ok;
+
+ lx_debug("%s: reading lx_sigdeliver_frame_t @ %p\n", caller, lxsdfp);
+ if (uucopy(lxsdfp, &lxsdf, sizeof (lxsdf)) != 0) {
+ lx_debug("%s: failed to read lx_sigdeliver_frame_t @ %p\n",
+ lxsdfp);
+
+ copy_ok = B_FALSE;
+ } else {
+ lx_debug("%s: lxsdf: magic %p retucp %p sigucp %p\n", caller,
+ lxsdf.lxsdf_magic, lxsdf.lxsdf_retucp, lxsdf.lxsdf_sigucp);
+
+ copy_ok = B_TRUE;
+ }
+
+ /*
+ * lx_sigdeliver() pushes a lx_sigdeliver_frame_t onto the stack
+ * before it creates the struct lx_oldsigstack.
+ */
+ if (copy_ok && lxsdf.lxsdf_magic == LX_SIGRT_MAGIC) {
+ LX_SIGNAL_DELIVERY_FRAME_FOUND(lxsdfp);
+
+ /*
+ * The guard value is intact; use the context pointers stored
+ * in the signal delivery frame:
+ */
+ *sigucp = lxsdf.lxsdf_sigucp;
+ *retucp = lxsdf.lxsdf_retucp;
+
+ /*
+ * Ensure that the backup signal delivery chain is in sync with
+ * the frame we are returning via:
+ */
+ lxtsd->lxtsd_sigbackup = lxsdf.lxsdf_sigbackup;
+ } else {
+ /*
+ * The guard value was not intact. Either the program smashed
+ * the stack unintentionally, or worse: intentionally moved
+ * some parts of the signal delivery frame we constructed to
+ * another location before calling rt_sigreturn(2).
+ */
+ LX_SIGNAL_DELIVERY_FRAME_CORRUPT(lxsdfp);
+
+ if (lxtsd->lxtsd_sigbackup == NULL) {
+ /*
+ * There was no backup context to use, so we must
+ * kill the process.
+ */
+ if (copy_ok) {
+ lx_err_fatal("%s: sp 0x%p, expected 0x%x, "
+ "found 0x%lx!", caller, (void *)sp,
+ LX_SIGRT_MAGIC,
+ (unsigned long)lxsdf.lxsdf_magic);
+ } else {
+ lx_err_fatal("%s: sp 0x%p, could not read "
+ "magic", caller, (void *)sp);
+ }
+ }
+
+ /*
+ * Attempt to recover by using the backup signal delivery
+ * chain:
+ */
+ lx_debug("%s: SIGRT_MAGIC not found @ sp %p; using backup "
+ "@ %p\n", caller, (void *)sp, lxtsd->lxtsd_sigbackup);
+ *sigucp = lxtsd->lxtsd_sigbackup->lxsb_sigucp;
+ *retucp = lxtsd->lxtsd_sigbackup->lxsb_retucp;
+ }
+}
+
+#if defined(_ILP32)
+/*
+ * Intercept the Linux sigreturn() syscall to turn it into the return through
+ * the libc call stack that Illumos expects.
+ *
+ * When control returns to libc's call_user_handler() routine, a setcontext(2)
+ * will be done that returns thread execution to the point originally
+ * interrupted by receipt of the signal.
+ *
+ * This is only used by 32-bit code.
+ */
+long
+lx_sigreturn(void)
+{
+ struct lx_oldsigstack *lx_ossp;
+ lx_sigset_t lx_sigset;
+ ucontext_t *ucp;
+ ucontext_t *sigucp;
+ ucontext_t *retucp;
+ uintptr_t sp;
+
+ ucp = lx_syscall_regs();
+
+ /*
+ * NOTE: The sp saved in the context is eight bytes off of where we
+ * need it to be (either due to trampoline or the copying of
+ * sp = uesp, not clear which).
+ */
+ sp = LX_REG(ucp, REG_SP) - 8;
+
+ /*
+ * At this point, the stack pointer should point to the struct
+ * lx_oldsigstack that lx_build_old_signal_frame() constructed and
+ * placed on the stack. We need to reference it a bit later, so
+ * save a pointer to it before incrementing our copy of the sp.
+ */
+ lx_ossp = (struct lx_oldsigstack *)sp;
+ sp += SA(sizeof (struct lx_oldsigstack));
+
+ lx_sigreturn_find_native_context(__func__, &sigucp, &retucp, sp);
+
+ /*
+ * We need to copy machine registers the Linux signal handler may have
+ * modified back to the Illumos ucontext_t.
+ *
+ * General registers copy across as-is, except Linux expects that
+ * changes made to uc_mcontext.gregs[ESP] will be reflected when the
+ * interrupted thread resumes execution after the signal handler. To
+ * emulate this behavior, we must modify uc_mcontext.gregs[UESP] to
+ * match uc_mcontext.gregs[ESP] as Illumos will restore the UESP
+ * value to ESP.
+ */
+ lx_ossp->sigc.sc_esp_at_signal = lx_ossp->sigc.sc_esp;
+ bcopy(&lx_ossp->sigc, &sigucp->uc_mcontext, sizeof (gregset_t));
+
+ LX_SIGRETURN(NULL, sigucp, sp);
+
+ /* copy back FP regs if present */
+ if (lx_ossp->sigc.sc_fpstate != NULL)
+ ltos_fpstate(&lx_ossp->fpstate, &sigucp->uc_mcontext.fpregs);
+
+ /* convert Linux signal mask back to its Illumos equivalent */
+ bzero(&lx_sigset, sizeof (lx_sigset_t));
+ lx_sigset.__bits[0] = lx_ossp->sigc.sc_mask;
+ lx_sigset.__bits[1] = lx_ossp->sig_extra;
+ (void) ltos_sigset(&lx_sigset, &sigucp->uc_sigmask);
+
+ /*
+ * For signal mask handling to be done properly, this call needs to
+ * return to the libc routine that originally called the signal handler
+ * rather than directly set the context back to the place the signal
+ * interrupted execution as the original Linux code would do.
+ */
+ lx_debug("lx_sigreturn: calling setcontext; retucp %p flags %lx "
+ "link %p\n", retucp, retucp->uc_flags, retucp->uc_link);
+ (void) setcontext(retucp);
+ assert(0);
+
+ /*NOTREACHED*/
+ return (0);
+}
+#endif
+
+/*
+ * This signal return syscall is used by both 32-bit and 64-bit code.
+ */
+long
+lx_rt_sigreturn(void)
+{
+ struct lx_sigstack *lx_ssp;
+ lx_ucontext_t *lx_ucp;
+ ucontext_t *ucp;
+ ucontext_t *sigucp;
+ ucontext_t *retucp;
+ uintptr_t sp;
+
+ /*
+ * Since we don't take the normal return path from this syscall, we
+ * inform the kernel that we're returning, for the sake of ptrace.
+ */
+ (void) syscall(SYS_brand, B_PTRACE_SIG_RETURN);
+
+ /* Get the registers at the emulated Linux rt_sigreturn syscall */
+ ucp = lx_syscall_regs();
+
+#if defined(_ILP32)
+ lx_debug("lx_rt_sigreturn: ESP %p UESP %p\n", LX_REG(ucp, ESP),
+ LX_REG(ucp, UESP));
+ /*
+ * For 32-bit
+ *
+ * NOTE: Because of the silly compatibility measures done in the
+ * signal trampoline code to make sure the stack holds the
+ * _exact same_ instruction sequence Linux does, we have to
+ * manually "pop" some extra instructions off the stack here
+ * before passing the stack address to the syscall because the
+ * trampoline code isn't allowed to do it due to the gdb
+ * compatability issues.
+ *
+ * No, I'm not kidding.
+ *
+ * The sp saved in the context is eight bytes off of where we
+ * need it to be (either due to trampoline or the copying of
+ * sp = uesp, not clear which but looks like the uesp case), so
+ * the need to pop the extra four byte instruction means we need
+ * to subtract a net four bytes from the sp before "popping" the
+ * struct lx_sigstack off the stack.
+ *
+ * This will yield the value the stack pointer had before
+ * lx_sigdeliver() created the stack frame for the Linux signal
+ * handler.
+ */
+ sp = (uintptr_t)LX_REG(ucp, REG_SP) - 4;
+#else
+ /*
+ * We need to make an adjustment for 64-bit code as well. Since 64-bit
+ * does not use the trampoline, it's probably for the same reason as
+ * alluded to above.
+ */
+ sp = (uintptr_t)LX_REG(ucp, REG_SP) - 8;
+#endif
+
+ /*
+ * At this point, the stack pointer should point to the struct
+ * lx_sigstack that lx_build_signal_frame() constructed and
+ * placed on the stack. We need to reference it a bit later, so
+ * save a pointer to it before incrementing our copy of the sp.
+ */
+ lx_ssp = (struct lx_sigstack *)sp;
+ sp += SA(sizeof (struct lx_sigstack));
+
+#if defined(_LP64)
+ /*
+ * The 64-bit lx_sigdeliver() inserts 8 bytes of padding between
+ * the lx_sigstack_t and the delivery frame to maintain ABI stack
+ * alignment.
+ */
+ sp += 8;
+#endif
+
+ lx_sigreturn_find_native_context(__func__, &sigucp, &retucp, sp);
+
+ /*
+ * We need to copy machine registers the Linux signal handler may have
+ * modified back to the Illumos version.
+ */
+#if defined(_LP64)
+ lx_ucp = &lx_ssp->uc;
+
+ /*
+ * General register layout is completely different.
+ */
+ LX_REG(sigucp, REG_R15) = lx_ucp->uc_sigcontext.sc_r15;
+ LX_REG(sigucp, REG_R14) = lx_ucp->uc_sigcontext.sc_r14;
+ LX_REG(sigucp, REG_R13) = lx_ucp->uc_sigcontext.sc_r13;
+ LX_REG(sigucp, REG_R12) = lx_ucp->uc_sigcontext.sc_r12;
+ LX_REG(sigucp, REG_R11) = lx_ucp->uc_sigcontext.sc_r11;
+ LX_REG(sigucp, REG_R10) = lx_ucp->uc_sigcontext.sc_r10;
+ LX_REG(sigucp, REG_R9) = lx_ucp->uc_sigcontext.sc_r9;
+ LX_REG(sigucp, REG_R8) = lx_ucp->uc_sigcontext.sc_r8;
+ LX_REG(sigucp, REG_RDI) = lx_ucp->uc_sigcontext.sc_rdi;
+ LX_REG(sigucp, REG_RSI) = lx_ucp->uc_sigcontext.sc_rsi;
+ LX_REG(sigucp, REG_RBP) = lx_ucp->uc_sigcontext.sc_rbp;
+ LX_REG(sigucp, REG_RBX) = lx_ucp->uc_sigcontext.sc_rbx;
+ LX_REG(sigucp, REG_RDX) = lx_ucp->uc_sigcontext.sc_rdx;
+ LX_REG(sigucp, REG_RCX) = lx_ucp->uc_sigcontext.sc_rcx;
+ LX_REG(sigucp, REG_RAX) = lx_ucp->uc_sigcontext.sc_rax;
+ LX_REG(sigucp, REG_TRAPNO) = lx_ucp->uc_sigcontext.sc_trapno;
+ LX_REG(sigucp, REG_ERR) = lx_ucp->uc_sigcontext.sc_err;
+ LX_REG(sigucp, REG_RIP) = lx_ucp->uc_sigcontext.sc_rip;
+ LX_REG(sigucp, REG_CS) = lx_ucp->uc_sigcontext.sc_cs;
+ LX_REG(sigucp, REG_RFL) = lx_ucp->uc_sigcontext.sc_eflags;
+ LX_REG(sigucp, REG_RSP) = lx_ucp->uc_sigcontext.sc_rsp;
+ LX_REG(sigucp, REG_SS) = lx_ucp->uc_sigcontext.sc_pad0;
+ LX_REG(sigucp, REG_FS) = lx_ucp->uc_sigcontext.sc_fs;
+ LX_REG(sigucp, REG_GS) = lx_ucp->uc_sigcontext.sc_gs;
+
+#else /* is _ILP32 */
+ lx_ucp = &lx_ssp->uc;
+
+ /*
+ * Illumos and Linux both follow the SysV i386 ABI layout for the
+ * mcontext.
+ *
+ * General registers copy across as-is, except Linux expects that
+ * changes made to uc_mcontext.gregs[ESP] will be reflected when the
+ * interrupted thread resumes execution after the signal handler. To
+ * emulate this behavior, we must modify uc_mcontext.gregs[UESP] to
+ * match uc_mcontext.gregs[ESP] as Illumos will restore the UESP value
+ * to ESP.
+ */
+ lx_ucp->uc_sigcontext.sc_esp_at_signal = lx_ucp->uc_sigcontext.sc_esp;
+
+ bcopy(&lx_ucp->uc_sigcontext, &sigucp->uc_mcontext.gregs,
+ sizeof (gregset_t));
+#endif
+
+ LX_SIGRETURN(lx_ucp, sigucp, sp);
+
+ if (lx_ucp->uc_sigcontext.sc_fpstate != NULL) {
+ ltos_fpstate(lx_ucp->uc_sigcontext.sc_fpstate,
+ &sigucp->uc_mcontext.fpregs);
+ }
+
+ /*
+ * Convert the Linux signal mask and stack back to their
+ * Illumos equivalents.
+ */
+ (void) ltos_sigset(&lx_ucp->uc_sigmask, &sigucp->uc_sigmask);
+ ltos_stack(&lx_ucp->uc_stack, &sigucp->uc_stack);
+
+ /*
+ * For signal mask handling to be done properly, this call needs to
+ * return to the libc routine that originally called the signal handler
+ * rather than directly set the context back to the place the signal
+ * interrupted execution as the original Linux code would do.
+ */
+ lx_debug("lx_rt_sigreturn: calling setcontext; retucp %p\n", retucp);
+ (void) setcontext(retucp);
+ assert(0);
+
+ /*NOTREACHED*/
+ return (0);
+}
+
+
+#if defined(_ILP32)
+/*
+ * Build signal frame for processing for "old" (legacy) Linux signals
+ * This stack-builder function is only used by 32-bit code.
+ */
+/* ARGSUSED4 */
+static void
+lx_build_old_signal_frame(int lx_sig, siginfo_t *sip, void *p, void *sp,
+ uintptr_t *hargs)
+{
+ extern void lx_sigreturn_tramp();
+
+ lx_sigset_t lx_sigset;
+ ucontext_t *ucp = (ucontext_t *)p;
+ struct lx_sigaction *lxsap;
+ struct lx_oldsigstack *lx_ossp = sp;
+
+ lx_debug("building old signal frame for lx sig %d at 0x%p", lx_sig, sp);
+
+ lx_ossp->sig = lx_sig;
+ lxsap = &lx_sighandlers.lx_sa[lx_sig];
+ lx_debug("lxsap @ 0x%p", lxsap);
+
+ if (lxsap && (lxsap->lxsa_flags & LX_SA_RESTORER) &&
+ lxsap->lxsa_restorer) {
+ lx_ossp->retaddr = lxsap->lxsa_restorer;
+ lx_debug("lxsa_restorer exists @ 0x%p", lx_ossp->retaddr);
+ } else {
+ lx_ossp->retaddr = lx_sigreturn_tramp;
+ lx_debug("lx_ossp->retaddr set to 0x%p", lx_sigreturn_tramp);
+ }
+
+ lx_debug("osf retaddr = 0x%p", lx_ossp->retaddr);
+
+ /* convert Illumos signal mask and stack to their Linux equivalents */
+ (void) stol_sigset(&ucp->uc_sigmask, &lx_sigset);
+ lx_ossp->sigc.sc_mask = lx_sigset.__bits[0];
+ lx_ossp->sig_extra = lx_sigset.__bits[1];
+
+ /*
+ * General registers copy across as-is, except Linux expects that
+ * uc_mcontext.gregs[ESP] == uc_mcontext.gregs[UESP] on receipt of a
+ * signal.
+ */
+ bcopy(&ucp->uc_mcontext, &lx_ossp->sigc, sizeof (gregset_t));
+ lx_ossp->sigc.sc_esp = lx_ossp->sigc.sc_esp_at_signal;
+
+ /*
+ * cr2 contains the faulting address, and Linux only sets cr2 for a
+ * a segmentation fault.
+ */
+ lx_ossp->sigc.sc_cr2 = (((lx_sig == LX_SIGSEGV) && (sip)) ?
+ (uintptr_t)sip->si_addr : 0);
+
+ /* convert FP regs if present */
+ if (ucp->uc_flags & UC_FPU) {
+ stol_fpstate(&ucp->uc_mcontext.fpregs, &lx_ossp->fpstate);
+ lx_ossp->sigc.sc_fpstate = &lx_ossp->fpstate;
+ } else {
+ lx_ossp->sigc.sc_fpstate = NULL;
+ }
+
+ /*
+ * Believe it or not, gdb wants to SEE the trampoline code on the
+ * bottom of the stack to determine whether the stack frame belongs to
+ * a signal handler, even though this code is no longer actually
+ * called.
+ *
+ * You can't make this stuff up.
+ */
+ bcopy((void *)lx_sigreturn_tramp, lx_ossp->trampoline,
+ sizeof (lx_ossp->trampoline));
+}
+#endif
+
+/*
+ * Build stack frame (32-bit) or stack local data (64-bit) for processing for
+ * modern Linux signals. This is the only stack-builder function for 64-bit
+ * code (32-bit code also calls this when using "modern" signals).
+ */
+/* ARGSUSED4 */
+static void
+lx_build_signal_frame(int lx_sig, siginfo_t *sip, void *p, void *sp,
+ uintptr_t *hargs)
+{
+ extern void lx_rt_sigreturn_tramp();
+
+ lx_ucontext_t *lx_ucp;
+ ucontext_t *ucp = (ucontext_t *)p;
+ struct lx_sigstack *lx_ssp = sp;
+ struct lx_sigaction *lxsap;
+
+ lx_debug("building signal frame for lx sig %d at 0x%p", lx_sig, sp);
+
+ lx_ucp = &lx_ssp->uc;
+#if defined(_ILP32)
+ /*
+ * Arguments are passed to the 32-bit signal handler on the stack.
+ */
+ lx_ssp->ucp = lx_ucp;
+ lx_ssp->sip = sip != NULL ? &lx_ssp->si : NULL;
+ lx_ssp->sig = lx_sig;
+#else
+ /*
+ * Arguments to the 64-bit signal handler are passed in registers:
+ * hdlr(int sig, siginfo_t *sip, void *ucp);
+ */
+ hargs[0] = lx_sig;
+ hargs[1] = sip != NULL ? (uintptr_t)&lx_ssp->si : NULL;
+ hargs[2] = (uintptr_t)lx_ucp;
+#endif
+
+ lxsap = &lx_sighandlers.lx_sa[lx_sig];
+ lx_debug("lxsap @ 0x%p", lxsap);
+
+ if (lxsap && (lxsap->lxsa_flags & LX_SA_RESTORER) &&
+ lxsap->lxsa_restorer) {
+ /*
+ * lxsa_restorer is explicitly set by sigaction in 32-bit code
+ * but it can also be implicitly set for both 32 and 64 bit
+ * code via lx_sigaction_common when we bcopy the user-supplied
+ * lx_sigaction element into the proper slot in the sighandler
+ * array.
+ */
+ lx_ssp->retaddr = lxsap->lxsa_restorer;
+ lx_debug("lxsa_restorer exists @ 0x%p", lx_ssp->retaddr);
+ } else {
+ lx_ssp->retaddr = lx_rt_sigreturn_tramp;
+ lx_debug("lx_ssp->retaddr set to 0x%p", lx_rt_sigreturn_tramp);
+ }
+
+ /* Linux has these fields but always clears them to 0 */
+ lx_ucp->uc_flags = 0;
+ lx_ucp->uc_link = NULL;
+
+ /* convert Illumos signal mask and stack to their Linux equivalents */
+ (void) stol_sigset(&ucp->uc_sigmask, &lx_ucp->uc_sigmask);
+ stol_stack(&ucp->uc_stack, &lx_ucp->uc_stack);
+
+#if defined(_LP64)
+ /*
+ * General register layout is completely different.
+ */
+ lx_ucp->uc_sigcontext.sc_r8 = LX_REG(ucp, REG_R8);
+ lx_ucp->uc_sigcontext.sc_r9 = LX_REG(ucp, REG_R9);
+ lx_ucp->uc_sigcontext.sc_r10 = LX_REG(ucp, REG_R10);
+ lx_ucp->uc_sigcontext.sc_r11 = LX_REG(ucp, REG_R11);
+ lx_ucp->uc_sigcontext.sc_r12 = LX_REG(ucp, REG_R12);
+ lx_ucp->uc_sigcontext.sc_r13 = LX_REG(ucp, REG_R13);
+ lx_ucp->uc_sigcontext.sc_r14 = LX_REG(ucp, REG_R14);
+ lx_ucp->uc_sigcontext.sc_r15 = LX_REG(ucp, REG_R15);
+ lx_ucp->uc_sigcontext.sc_rdi = LX_REG(ucp, REG_RDI);
+ lx_ucp->uc_sigcontext.sc_rsi = LX_REG(ucp, REG_RSI);
+ lx_ucp->uc_sigcontext.sc_rbp = LX_REG(ucp, REG_RBP);
+ lx_ucp->uc_sigcontext.sc_rbx = LX_REG(ucp, REG_RBX);
+ lx_ucp->uc_sigcontext.sc_rdx = LX_REG(ucp, REG_RDX);
+ lx_ucp->uc_sigcontext.sc_rax = LX_REG(ucp, REG_RAX);
+ lx_ucp->uc_sigcontext.sc_rcx = LX_REG(ucp, REG_RCX);
+ lx_ucp->uc_sigcontext.sc_rsp = LX_REG(ucp, REG_RSP);
+ lx_ucp->uc_sigcontext.sc_rip = LX_REG(ucp, REG_RIP);
+ lx_ucp->uc_sigcontext.sc_eflags = LX_REG(ucp, REG_RFL);
+ lx_ucp->uc_sigcontext.sc_cs = LX_REG(ucp, REG_CS);
+ lx_ucp->uc_sigcontext.sc_gs = LX_REG(ucp, REG_GS);
+ lx_ucp->uc_sigcontext.sc_fs = LX_REG(ucp, REG_FS);
+ lx_ucp->uc_sigcontext.sc_pad0 = LX_REG(ucp, REG_SS);
+ lx_ucp->uc_sigcontext.sc_err = LX_REG(ucp, REG_ERR);
+ lx_ucp->uc_sigcontext.sc_trapno = LX_REG(ucp, REG_TRAPNO);
+
+#else /* is _ILP32 */
+ /*
+ * General registers copy across as-is, except Linux expects that
+ * uc_mcontext.gregs[ESP] == uc_mcontext.gregs[UESP] on receipt of a
+ * signal.
+ */
+ bcopy(&ucp->uc_mcontext, &lx_ucp->uc_sigcontext, sizeof (gregset_t));
+ lx_ucp->uc_sigcontext.sc_esp = lx_ucp->uc_sigcontext.sc_esp_at_signal;
+#endif
+
+ /*
+ * cr2 contains the faulting address, which Linux only sets for a
+ * a segmentation fault.
+ */
+ lx_ucp->uc_sigcontext.sc_cr2 = ((lx_sig == LX_SIGSEGV) && (sip)) ?
+ (uintptr_t)sip->si_addr : 0;
+
+ /*
+ * This should only return an error if the signum is invalid but that
+ * also gets converted into a LX_SIGKILL by this function.
+ */
+ if (sip != NULL)
+ (void) stol_siginfo(sip, &lx_ssp->si);
+ else
+ bzero(&lx_ssp->si, sizeof (lx_siginfo_t));
+
+ /* convert FP regs if present */
+ if (ucp->uc_flags & UC_FPU) {
+ /*
+ * Copy FP regs to the appropriate place in the the lx_sigstack
+ * structure.
+ */
+ stol_fpstate(&ucp->uc_mcontext.fpregs, &lx_ssp->fpstate);
+ lx_ucp->uc_sigcontext.sc_fpstate = &lx_ssp->fpstate;
+ } else {
+ lx_ucp->uc_sigcontext.sc_fpstate = NULL;
+ }
+
+#if defined(_ILP32)
+ /*
+ * Believe it or not, gdb wants to SEE the sigreturn code on the
+ * top of the stack to determine whether the stack frame belongs to
+ * a signal handler, even though this code is not actually called.
+ *
+ * You can't make this stuff up.
+ */
+ bcopy((void *)lx_rt_sigreturn_tramp, lx_ssp->trampoline,
+ sizeof (lx_ssp->trampoline));
+#endif
+}
+
+/*
+ * This is the interposition handler for Linux signals.
+ */
+static void
+lx_call_user_handler(int sig, siginfo_t *sip, void *p)
+{
+ void (*user_handler)();
+ void (*stk_builder)();
+ struct lx_sigaction *lxsap;
+ ucontext_t *ucp = (ucontext_t *)p;
+ size_t stksize;
+ int lx_sig;
+
+ /*
+ * If Illumos signal has no Linux equivalent, effectively ignore it.
+ */
+ if ((lx_sig = stol_signo[sig]) == -1) {
+ lx_unsupported("caught Illumos signal %d, no Linux equivalent",
+ sig);
+ return;
+ }
+
+ lx_debug("interpose caught Illumos signal %d, translating to Linux "
+ "signal %d", sig, lx_sig);
+
+ lxsap = &lx_sighandlers.lx_sa[lx_sig];
+ lx_debug("lxsap @ 0x%p", lxsap);
+
+ if ((sig == SIGPWR) && (lxsap->lxsa_handler == SIG_DFL)) {
+ /*
+ * Linux SIG_DFL for SIGPWR is to terminate. The lx wait
+ * emulation will translate SIGPWR to LX_SIGPWR.
+ */
+ (void) syscall(SYS_brand, B_EXIT_AS_SIG, SIGPWR);
+ /* This should never return */
+ assert(0);
+ }
+
+ if (lxsap->lxsa_handler == SIG_DFL || lxsap->lxsa_handler == SIG_IGN)
+ lx_err_fatal("lxsa_handler set to %s? How?!?!?",
+ (lxsap->lxsa_handler == SIG_DFL) ? "SIG_DFL" : "SIG_IGN");
+
+#if defined(_LP64)
+ stksize = sizeof (struct lx_sigstack);
+ stk_builder = lx_build_signal_frame;
+#else
+ if (lxsap->lxsa_flags & LX_SA_SIGINFO) {
+ stksize = sizeof (struct lx_sigstack);
+ stk_builder = lx_build_signal_frame;
+ } else {
+ stksize = sizeof (struct lx_oldsigstack);
+ stk_builder = lx_build_old_signal_frame;
+ }
+#endif
+
+ user_handler = lxsap->lxsa_handler;
+
+ lx_debug("delivering %d (lx %d) to handler at 0x%p", sig, lx_sig,
+ lxsap->lxsa_handler);
+
+ if (lxsap->lxsa_flags & LX_SA_RESETHAND)
+ lxsap->lxsa_handler = SIG_DFL;
+
+ lx_sigdeliver(lx_sig, sip, ucp, stksize, stk_builder, user_handler,
+ lxsap);
+
+ /*
+ * We need to handle restarting system calls if requested by the
+ * program for this signal type:
+ */
+ if (lxsap->lxsa_flags & LX_SA_RESTART) {
+ uintptr_t flags = (uintptr_t)ucp->uc_brand_data[0];
+ long ret = (long)LX_REG(ucp, REG_R0);
+ boolean_t interrupted = (ret == -lx_errno(EINTR, -1));
+
+ /*
+ * If the system call returned EINTR, and the system
+ * call handler set "br_syscall_restart" when returning,
+ * we modify the context to try the system call again
+ * when we return from this signal handler.
+ */
+ if ((flags & LX_UC_RESTART_SYSCALL) && interrupted) {
+ int syscall_num = (int)(uintptr_t)ucp->uc_brand_data[2];
+
+ lx_debug("restarting interrupted system call %d",
+ syscall_num);
+
+ /*
+ * Both the "int 0x80" and the "syscall" instruction
+ * are two bytes long. Wind the program counter back
+ * to the start of this instruction.
+ *
+ * The system call we interrupted is preserved in the
+ * brand-specific data in the ucontext_t when the
+ * LX_UC_RESTART_SYSCALL flag is set. This is
+ * analogous to the "orig_[er]ax" field in the Linux
+ * "user_regs_struct".
+ */
+ LX_REG(ucp, REG_PC) -= 2;
+ LX_REG(ucp, REG_R0) = syscall_num;
+ }
+ }
+}
+
+/*
+ * The "lx_sigdeliver()" function is responsible for constructing the emulated
+ * signal delivery frame on the brand stack for this LWP. A context is saved
+ * on the stack which will be used by the "sigreturn(2)" family of emulated
+ * system calls to get us back here after the Linux signal handler returns.
+ * This function is modelled on the in-kernel "sendsig()" signal delivery
+ * mechanism.
+ */
+void
+lx_sigdeliver(int lx_sig, siginfo_t *sip, ucontext_t *ucp, size_t stacksz,
+ void (*stack_builder)(), void (*user_handler)(),
+ struct lx_sigaction *lxsap)
+{
+ lx_sigbackup_t sigbackup;
+ ucontext_t uc;
+ lx_tsd_t *lxtsd = lx_get_tsd();
+ int totsz = 0;
+ uintptr_t flags;
+ uintptr_t hargs[3];
+ uintptr_t orig_sp = 0;
+
+ /*
+ * These variables must be "volatile", as they are modified after the
+ * getcontext() stores the register state:
+ */
+ volatile boolean_t signal_delivered = B_FALSE;
+ volatile boolean_t sp_modified = B_FALSE;
+ volatile uintptr_t lxfp = 0;
+ volatile uintptr_t old_tsd_sp = 0;
+ volatile int newstack = 0;
+
+ /*
+ * This function involves modifying the Linux process stack for this
+ * thread. To do so without corruption requires us to exclude other
+ * signal handlers (or emulated system calls called from within those
+ * handlers) from running while we reserve space on that stack. We
+ * defer the execution of further instances of lx_call_user_handler()
+ * until we have completed this operation.
+ */
+ _sigoff();
+
+ /*
+ * Clear register arguments vector.
+ */
+ bzero(hargs, sizeof (hargs));
+
+ /* Save our SP so we can restore it after coming back in. */
+ orig_sp = LX_REG(ucp, REG_SP);
+
+ /*
+ * We save a context here so that we can be returned later to complete
+ * handling the signal.
+ */
+ lx_debug("lx_sigdeliver: STORING RETURN CONTEXT @ %p\n", &uc);
+ assert(getcontext(&uc) == 0);
+ lx_debug("lx_sigdeliver: RETURN CONTEXT %p LINK %p FLAGS %lx\n",
+ &uc, uc.uc_link, uc.uc_flags);
+ if (signal_delivered) {
+ /*
+ * If the "signal_delivered" flag is set, we are returned here
+ * via setcontext() as called by the emulated Linux signal
+ * return system call.
+ */
+ lx_debug("lx_sigdeliver: WE ARE BACK, VIA UC @ %p!\n", &uc);
+
+ if (sp_modified) {
+ /*
+ * Restore the original stack pointer, which we saved
+ * on our alt. stack, back into the context.
+ */
+ LX_REG(ucp, REG_SP) = orig_sp;
+ }
+
+ goto after_signal_handler;
+ }
+ signal_delivered = B_TRUE;
+
+ /*
+ * Preserve the current tsd value of the Linux process stack pointer,
+ * even if it is zero. We will restore it when we are returned here
+ * via setcontext() after the Linux process has completed execution of
+ * its signal handler.
+ */
+ old_tsd_sp = lxtsd->lxtsd_lx_sp;
+
+ /*
+ * Figure out whether we will be handling this signal on an alternate
+ * stack specified by the user.
+ */
+ newstack = (lxsap->lxsa_flags & LX_SA_ONSTACK) &&
+ !(lxtsd->lxtsd_sigaltstack.ss_flags & (LX_SS_ONSTACK |
+ LX_SS_DISABLE));
+
+ /*
+ * Find the first unused region of the Linux process stack, where
+ * we will assemble our signal delivery frame.
+ */
+ flags = (uintptr_t)ucp->uc_brand_data[0];
+ if (newstack) {
+ /*
+ * We are moving to the user-provided alternate signal
+ * stack.
+ */
+ lxfp = SA((uintptr_t)lxtsd->lxtsd_sigaltstack.ss_sp) +
+ SA(lxtsd->lxtsd_sigaltstack.ss_size) - STACK_ALIGN;
+ lx_debug("lx_sigdeliver: moving to ALTSTACK sp %p\n", lxfp);
+ LX_SIGNAL_ALTSTACK_ENABLE(lxfp);
+ } else if (flags & LX_UC_STACK_BRAND) {
+ /*
+ * We interrupted the Linux process to take this signal. The
+ * stack pointer is the one saved in this context.
+ */
+ lxfp = LX_REG(ucp, REG_SP);
+ } else {
+ /*
+ * We interrupted a native (emulation) routine, so we must get
+ * the current stack pointer from either the tsd (if one is
+ * stored there) or via the context chain.
+ *
+ */
+ lxfp = lx_find_brand_sp();
+ if (lxtsd->lxtsd_lx_sp != 0) {
+ /*
+ * We must also make room for the possibility of nested
+ * signal delivery -- we may be pre-empting the
+ * in-progress handling of another signal.
+ *
+ * Note that if we were already on the alternate stack,
+ * any emulated Linux system calls would be betwixt
+ * that original signal frame and this new one on the
+ * one contiguous stack, so this logic holds either
+ * way:
+ */
+ lxfp = MIN(lxtsd->lxtsd_lx_sp, lxfp);
+ }
+
+ /* Replace the context SP with the one from the Linux context */
+ LX_REG(ucp, REG_SP) = lxfp;
+ sp_modified = B_TRUE;
+ }
+
+ /*
+ * Account for a reserved stack region (for amd64, this is 128 bytes),
+ * and align the stack:
+ */
+ lxfp -= STACK_RESERVE;
+ lxfp &= ~(STACK_ALIGN - 1);
+
+ /*
+ * Allocate space on the Linux process stack for our delivery frame,
+ * including:
+ *
+ * ----------------------------------------------------- old %sp
+ * - lx_sigdeliver_frame_t
+ * - (ucontext_t pointers and stack magic)
+ * -----------------------------------------------------
+ * - (amd64-only 8-byte alignment gap)
+ * -----------------------------------------------------
+ * - frame of size "stacksz" from the stack builder
+ * ----------------------------------------------------- new %sp
+ */
+#if defined(_LP64)
+ /*
+ * The AMD64 ABI requires us to align the stack such that when the
+ * called function pushes the base pointer, the stack is 16 byte
+ * aligned. The stack must, therefore, be 8- but _not_ 16-byte
+ * aligned.
+ */
+#if (STACK_ALIGN != 16) || (STACK_ENTRY_ALIGN != 8)
+#error "lx_sigdeliver() did not find expected stack alignment"
+#endif
+ totsz = SA(sizeof (lx_sigdeliver_frame_t)) + SA(stacksz) + 8;
+ assert((totsz & (STACK_ENTRY_ALIGN - 1)) == 0);
+ assert((totsz & (STACK_ALIGN - 1)) == 8);
+#else
+ totsz = SA(sizeof (lx_sigdeliver_frame_t)) + SA(stacksz);
+ assert((totsz & (STACK_ALIGN - 1)) == 0);
+#endif
+
+ /*
+ * Copy our return frame into place:
+ */
+ lxfp -= SA(sizeof (lx_sigdeliver_frame_t));
+ lx_debug("lx_sigdeliver: lx_sigdeliver_frame_t @ %p\n", lxfp);
+ {
+ lx_sigdeliver_frame_t frm;
+
+ frm.lxsdf_magic = LX_SIGRT_MAGIC;
+ frm.lxsdf_retucp = &uc;
+ frm.lxsdf_sigucp = ucp;
+ frm.lxsdf_sigbackup = &sigbackup;
+
+ lx_debug("lx_sigdeliver: retucp %p sigucp %p\n",
+ frm.lxsdf_retucp, frm.lxsdf_sigucp);
+
+ if (uucopy(&frm, (void *)lxfp, sizeof (frm)) != 0) {
+ /*
+ * We could not modify the stack of the emulated Linux
+ * program. Act like the kernel and terminate the
+ * program with a segmentation violation.
+ */
+ (void) syscall(SYS_brand, B_EXIT_AS_SIG, SIGSEGV);
+ }
+
+ LX_SIGNAL_DELIVERY_FRAME_CREATE((void *)lxfp);
+
+ /*
+ * Populate a backup copy of signal linkage to use in case
+ * the Linux program completely destroys (or relocates) the
+ * delivery frame.
+ *
+ * This is necessary for programs that have flown so far off
+ * the architectural rails that they believe it is
+ * acceptable to make assumptions about the precise size and
+ * layout of the signal handling frame assembled by the
+ * kernel.
+ */
+ sigbackup.lxsb_retucp = frm.lxsdf_retucp;
+ sigbackup.lxsb_sigucp = frm.lxsdf_sigucp;
+ sigbackup.lxsb_sigdeliver_frame = lxfp;
+ sigbackup.lxsb_previous = lxtsd->lxtsd_sigbackup;
+ lxtsd->lxtsd_sigbackup = &sigbackup;
+
+ lx_debug("lx_sigdeliver: installed sigbackup %p; prev %p\n",
+ &sigbackup, sigbackup.lxsb_previous);
+ }
+
+ /*
+ * Build the Linux signal handling frame:
+ */
+#if defined(_LP64)
+ lxfp -= SA(stacksz) + 8;
+#else
+ lxfp -= SA(stacksz);
+#endif
+ lx_debug("lx_sigdeliver: Linux sig frame @ %p\n", lxfp);
+ stack_builder(lx_sig, sip, ucp, lxfp, hargs);
+
+ /*
+ * Record our reservation so that any nested signal handlers
+ * can see it.
+ */
+ lx_debug("lx_sigdeliver: Linux tsd sp %p -> %p\n", lxtsd->lxtsd_lx_sp,
+ lxfp);
+ lxtsd->lxtsd_lx_sp = lxfp;
+
+ if (newstack) {
+ lxtsd->lxtsd_sigaltstack.ss_flags |= LX_SS_ONSTACK;
+ }
+
+ LX_SIGDELIVER(lx_sig, lxsap, (void *)lxfp);
+
+ /*
+ * Re-enable signal delivery. If a signal was queued while we were
+ * in the critical section, it will be delivered immediately.
+ */
+ _sigon();
+
+ /*
+ * Pass control to the Linux signal handler:
+ */
+ lx_debug("lx_sigdeliver: JUMPING TO LINUX (sig %d sp %p eip %p)\n",
+ lx_sig, lxfp, user_handler);
+ {
+ ucontext_t jump_uc;
+
+ bcopy(lx_find_brand_uc(), &jump_uc, sizeof (jump_uc));
+
+ /*
+ * We want to load the general registers from this context, and
+ * switch to the BRAND stack. We do _not_ want to restore the
+ * uc_link value from this synthetic context, as that would
+ * break the signal handling context chain.
+ */
+ jump_uc.uc_flags = UC_CPU;
+ jump_uc.uc_brand_data[0] = (void *)(LX_UC_STACK_BRAND |
+ LX_UC_IGNORE_LINK);
+
+ LX_REG(&jump_uc, REG_FP) = 0;
+ LX_REG(&jump_uc, REG_SP) = lxfp;
+ LX_REG(&jump_uc, REG_PC) = (uintptr_t)user_handler;
+
+#if defined(_LP64)
+ /*
+ * Pass signal handler arguments by registers on AMD64.
+ */
+ LX_REG(&jump_uc, REG_RDI) = hargs[0];
+ LX_REG(&jump_uc, REG_RSI) = hargs[1];
+ LX_REG(&jump_uc, REG_RDX) = hargs[2];
+#endif
+
+ lx_jump_to_linux(&jump_uc);
+ }
+
+ assert(0);
+ abort();
+
+after_signal_handler:
+ /*
+ * Ensure all nested signal handlers have completed correctly
+ * and then remove our stack reservation.
+ */
+ _sigoff();
+ LX_SIGNAL_POST_HANDLER(lxfp, old_tsd_sp);
+ assert(lxtsd->lxtsd_lx_sp == lxfp);
+ lx_debug("lx_sigdeliver: after; Linux tsd sp %p -> %p\n", lxfp,
+ old_tsd_sp);
+ lxtsd->lxtsd_lx_sp = old_tsd_sp;
+ if (newstack) {
+ LX_SIGNAL_ALTSTACK_DISABLE();
+ lx_debug("lx_sigdeliver: disabling ALTSTACK sp %p\n", lxfp);
+ lxtsd->lxtsd_sigaltstack.ss_flags &= ~LX_SS_ONSTACK;
+ }
+ /*
+ * Restore backup signal tracking chain pointer to previous value:
+ */
+ if (lxtsd->lxtsd_sigbackup != NULL) {
+ lx_sigbackup_t *bprev = lxtsd->lxtsd_sigbackup->lxsb_previous;
+
+ lx_debug("lx_sigdeliver: restoring sigbackup %p to %p\n",
+ lxtsd->lxtsd_sigbackup, bprev);
+
+ lxtsd->lxtsd_sigbackup = bprev;
+ }
+ _sigon();
+
+ /*
+ * Here we return to libc so that it may clean up and restore the
+ * context originally interrupted by this signal.
+ */
+}
+
+/*
+ * Common routine to modify sigaction characteristics of a thread.
+ *
+ * We shouldn't need any special locking code here as we actually use our copy
+ * of libc's sigaction() to do all the real work, so its thread locking should
+ * take care of any issues for us.
+ */
+static int
+lx_sigaction_common(int lx_sig, struct lx_sigaction *lxsp,
+ struct lx_sigaction *olxsp)
+{
+ struct lx_sigaction *lxsap;
+ struct sigaction sa;
+
+ if (lx_sig <= 0 || lx_sig > LX_NSIG)
+ return (-EINVAL);
+
+ lxsap = &lx_sighandlers.lx_sa[lx_sig];
+ lx_debug("&lx_sighandlers.lx_sa[%d] = 0x%p", lx_sig, lxsap);
+
+ if ((olxsp != NULL) &&
+ ((uucopy(lxsap, olxsp, sizeof (struct lx_sigaction))) != 0))
+ return (-errno);
+
+ if (lxsp != NULL) {
+ int err, sig;
+ struct lx_sigaction lxsa;
+ sigset_t new_set, oset;
+
+ if (uucopy(lxsp, &lxsa, sizeof (struct lx_sigaction)) != 0)
+ return (-errno);
+
+ if ((sig = ltos_signo[lx_sig]) != -1) {
+ if (lx_no_abort_handler) {
+ /*
+ * If LX_NO_ABORT_HANDLER has been set, we will
+ * not allow the emulated program to do
+ * anything hamfisted with SIGSEGV or SIGABRT
+ * signals.
+ */
+ if (sig == SIGSEGV || sig == SIGABRT) {
+ return (0);
+ }
+ }
+
+ /*
+ * Block this signal while messing with its dispostion
+ */
+ (void) sigemptyset(&new_set);
+ (void) sigaddset(&new_set, sig);
+
+ if (sigprocmask(SIG_BLOCK, &new_set, &oset) < 0) {
+ err = errno;
+ lx_debug("unable to block signal %d: %s", sig,
+ strerror(err));
+ return (-err);
+ }
+
+ /*
+ * We don't really need the old signal disposition at
+ * this point, but this weeds out signals that would
+ * cause sigaction() to return an error before we change
+ * anything other than the current signal mask.
+ */
+ if (sigaction(sig, NULL, &sa) < 0) {
+ err = errno;
+ lx_debug("sigaction() to get old "
+ "disposition for signal %d failed: "
+ "%s", sig, strerror(err));
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ return (-err);
+ }
+
+ if ((lxsa.lxsa_handler != SIG_DFL) &&
+ (lxsa.lxsa_handler != SIG_IGN)) {
+ sa.sa_handler = lx_call_user_handler;
+
+ /*
+ * The interposition signal handler needs the
+ * information provided via the SA_SIGINFO flag.
+ */
+ sa.sa_flags = SA_SIGINFO;
+
+ /*
+ * When translating from Linux to illumos
+ * sigaction(2) flags, we explicitly do not
+ * pass SA_ONSTACK to the kernel. The
+ * alternate stack for Linux signal handling is
+ * handled entirely by the emulation code.
+ */
+ if (lxsa.lxsa_flags & LX_SA_NOCLDSTOP)
+ sa.sa_flags |= SA_NOCLDSTOP;
+ if (lxsa.lxsa_flags & LX_SA_NOCLDWAIT)
+ sa.sa_flags |= SA_NOCLDWAIT;
+ if (lxsa.lxsa_flags & LX_SA_RESTART)
+ sa.sa_flags |= SA_RESTART;
+ if (lxsa.lxsa_flags & LX_SA_NODEFER)
+ sa.sa_flags |= SA_NODEFER;
+
+ /*
+ * RESETHAND cannot be used be passed through
+ * for SIGPWR due to different default actions
+ * between Linux and Illumos.
+ */
+ if ((sig != SIGPWR) &&
+ (lxsa.lxsa_flags & LX_SA_RESETHAND))
+ sa.sa_flags |= SA_RESETHAND;
+
+ if (ltos_sigset(&lxsa.lxsa_mask,
+ &sa.sa_mask) != 0) {
+ err = errno;
+ (void) sigprocmask(SIG_SETMASK, &oset,
+ NULL);
+ return (-err);
+ }
+
+ lx_debug("interposing handler @ 0x%p for "
+ "signal %d (lx %d), flags 0x%x",
+ lxsa.lxsa_handler, sig, lx_sig,
+ lxsa.lxsa_flags);
+
+ if (sigaction(sig, &sa, NULL) < 0) {
+ err = errno;
+ lx_debug("sigaction() to set new "
+ "disposition for signal %d failed: "
+ "%s", sig, strerror(err));
+ (void) sigprocmask(SIG_SETMASK, &oset,
+ NULL);
+ return (-err);
+ }
+ } else if ((sig != SIGPWR) ||
+ ((sig == SIGPWR) &&
+ (lxsa.lxsa_handler == SIG_IGN))) {
+ /*
+ * There's no need to interpose for SIG_DFL or
+ * SIG_IGN so just call our copy of libc's
+ * sigaction(), but don't allow SIG_DFL for
+ * SIGPWR due to differing default actions
+ * between Linux and Illumos.
+ *
+ * Get the previous disposition first so things
+ * like sa_mask and sa_flags are preserved over
+ * a transition to SIG_DFL or SIG_IGN, which is
+ * what Linux expects.
+ */
+
+ sa.sa_handler = lxsa.lxsa_handler;
+
+ if (sigaction(sig, &sa, NULL) < 0) {
+ err = errno;
+ lx_debug("sigaction(%d, %s) failed: %s",
+ sig, ((sa.sa_handler == SIG_DFL) ?
+ "SIG_DFL" : "SIG_IGN"),
+ strerror(err));
+ (void) sigprocmask(SIG_SETMASK, &oset,
+ NULL);
+ return (-err);
+ }
+ }
+ } else {
+ lx_debug("Linux signal with no kill support "
+ "specified: %d", lx_sig);
+ }
+
+ /*
+ * Save the new disposition for the signal in the global
+ * lx_sighandlers structure.
+ */
+ bcopy(&lxsa, lxsap, sizeof (struct lx_sigaction));
+
+ /*
+ * Reset the signal mask to what we came in with if
+ * we were modifying a kill-supported signal.
+ */
+ if (sig != -1)
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+ }
+
+ return (0);
+}
+
+#if defined(_ILP32)
+/*
+ * sigaction is only used in 32-bit code.
+ */
+long
+lx_sigaction(uintptr_t lx_sig, uintptr_t actp, uintptr_t oactp)
+{
+ int val;
+ struct lx_sigaction sa, osa;
+ struct lx_sigaction *sap, *osap;
+ struct lx_osigaction *osp;
+
+ sap = (actp ? &sa : NULL);
+ osap = (oactp ? &osa : NULL);
+
+ /*
+ * If we have a source pointer, convert source lxsa_mask from
+ * lx_osigset_t to lx_sigset_t format.
+ */
+ if (sap) {
+ osp = (struct lx_osigaction *)actp;
+ sap->lxsa_handler = osp->lxsa_handler;
+
+ bzero(&sap->lxsa_mask, sizeof (lx_sigset_t));
+
+ for (val = 1; val <= OSIGSET_NBITS; val++)
+ if (osp->lxsa_mask & OSIGSET_BITSET(val))
+ (void) lx_sigaddset(&sap->lxsa_mask, val);
+
+ sap->lxsa_flags = osp->lxsa_flags;
+ sap->lxsa_restorer = osp->lxsa_restorer;
+ }
+
+ if ((val = lx_sigaction_common(lx_sig, sap, osap)))
+ return (val);
+
+ /*
+ * If we have a save pointer, convert the old lxsa_mask from
+ * lx_sigset_t to lx_osigset_t format.
+ */
+ if (osap) {
+ osp = (struct lx_osigaction *)oactp;
+
+ osp->lxsa_handler = osap->lxsa_handler;
+
+ bzero(&osp->lxsa_mask, sizeof (osp->lxsa_mask));
+ for (val = 1; val <= OSIGSET_NBITS; val++)
+ if (lx_sigismember(&osap->lxsa_mask, val))
+ osp->lxsa_mask |= OSIGSET_BITSET(val);
+
+ osp->lxsa_flags = osap->lxsa_flags;
+ osp->lxsa_restorer = osap->lxsa_restorer;
+ }
+
+ return (0);
+}
+#endif
+
+long
+lx_rt_sigaction(uintptr_t lx_sig, uintptr_t actp, uintptr_t oactp,
+ uintptr_t setsize)
+{
+ /*
+ * The "new" rt_sigaction call checks the setsize
+ * parameter.
+ */
+ if ((size_t)setsize != sizeof (lx_sigset_t))
+ return (-EINVAL);
+
+ return (lx_sigaction_common(lx_sig, (struct lx_sigaction *)actp,
+ (struct lx_sigaction *)oactp));
+}
+
+#if defined(_ILP32)
+/*
+ * Convert signal syscall to a call to the lx_sigaction() syscall
+ * Only used in 32-bit code.
+ */
+long
+lx_signal(uintptr_t lx_sig, uintptr_t handler)
+{
+ struct sigaction act;
+ struct sigaction oact;
+ int rc;
+
+ /*
+ * Use sigaction to mimic SYSV signal() behavior; glibc will
+ * actually call sigaction(2) itself, so we're really reaching
+ * back for signal(2) semantics here.
+ */
+ bzero(&act, sizeof (act));
+ act.sa_handler = (void (*)())handler;
+ act.sa_flags = SA_RESETHAND | SA_NODEFER;
+
+ rc = lx_sigaction(lx_sig, (uintptr_t)&act, (uintptr_t)&oact);
+ return ((rc == 0) ? ((ssize_t)oact.sa_handler) : rc);
+}
+#endif
+
+void
+lx_sighandlers_save(lx_sighandlers_t *saved)
+{
+ bcopy(&lx_sighandlers, saved, sizeof (lx_sighandlers_t));
+}
+
+void
+lx_sighandlers_restore(lx_sighandlers_t *saved)
+{
+ bcopy(saved, &lx_sighandlers, sizeof (lx_sighandlers_t));
+}
+
+int
+lx_siginit(void)
+{
+ extern void set_setcontext_enforcement(int);
+ extern void set_escaped_context_cleanup(int);
+
+ struct sigaction sa;
+ sigset_t new_set, oset;
+ int lx_sig, sig;
+
+ /*
+ * Block all signals possible while setting up the signal imposition
+ * mechanism.
+ */
+ (void) sigfillset(&new_set);
+
+ if (sigprocmask(SIG_BLOCK, &new_set, &oset) < 0)
+ lx_err_fatal("unable to block signals while setting up "
+ "imposition mechanism: %s", strerror(errno));
+
+ /*
+ * Ignore any signals that have no Linux analog so that those
+ * signals cannot be sent to Linux processes from the global zone
+ */
+ for (sig = 1; sig < NSIG; sig++)
+ if (stol_signo[sig] < 0)
+ (void) sigignore(sig);
+
+ /*
+ * Mark any signals that are ignored as ignored in our interposition
+ * handler array
+ */
+ for (lx_sig = 1; lx_sig <= LX_NSIG; lx_sig++) {
+ if (((sig = ltos_signo[lx_sig]) != -1) &&
+ (sigaction(sig, NULL, &sa) < 0))
+ lx_err_fatal("unable to determine previous disposition "
+ "for signal %d: %s", sig, strerror(errno));
+
+ if (sa.sa_handler == SIG_IGN) {
+ lx_debug("marking signal %d (lx %d) as SIG_IGN",
+ sig, lx_sig);
+ lx_sighandlers.lx_sa[lx_sig].lxsa_handler = SIG_IGN;
+ }
+ }
+
+ /*
+ * Have our interposition handler handle SIGPWR to start with,
+ * as it has a default action of terminating the process in Linux
+ * but its default is to be ignored in Illumos.
+ */
+ (void) sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = lx_call_user_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGPWR, &sa, NULL) < 0)
+ lx_err_fatal("sigaction(SIGPWR) failed: %s", strerror(errno));
+
+ /*
+ * Illumos' libc forces certain register values in the ucontext_t
+ * used to restore a post-signal user context to be those Illumos
+ * expects; however that is not what we want to happen if the signal
+ * was taken while branded code was executing, so we must disable
+ * that behavior.
+ */
+ set_setcontext_enforcement(0);
+
+ /*
+ * The illumos libc attempts to clean up dangling uc_link pointers in
+ * signal handling contexts when libc believes us to have escaped a
+ * signal handler incorrectly in the past. We want to disable this
+ * behaviour, so that the system call emulation context saved by the
+ * kernel brand module for lx_emulate() may be part of the context
+ * chain without itself being used for signal handling.
+ */
+ set_escaped_context_cleanup(0);
+
+ /*
+ * Reset the signal mask to what we came in with.
+ */
+ (void) sigprocmask(SIG_SETMASK, &oset, NULL);
+
+ lx_debug("interposition handler setup for SIGPWR");
+ return (0);
+}
+
+/*
+ * The first argument is the pid (Linux tgid) to send the signal to, second
+ * argument is the signal to send (an lx signal), and third is the siginfo_t
+ * with extra information. We translate the code and signal only from the
+ * siginfo_t, and leave everything else the same as it gets passed through the
+ * signalling system. This is enough to get sigqueue working. See Linux man
+ * page rt_sigqueueinfo(2).
+ */
+long
+lx_rt_sigqueueinfo(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ pid_t tgid = (pid_t)p1;
+ int lx_sig = (int)p2;
+ int sig;
+ lx_siginfo_t lx_siginfo;
+ siginfo_t siginfo;
+ int s_code;
+ pid_t s_pid;
+
+ if (uucopy((void *)p3, &lx_siginfo, sizeof (lx_siginfo_t)) != 0)
+ return (-EFAULT);
+ s_code = ltos_sigcode(lx_siginfo.lsi_code);
+ if (s_code == LX_SI_CODE_NOT_EXIST)
+ return (-EINVAL);
+ if (lx_sig < 0 || lx_sig > LX_NSIG || (sig = ltos_signo[lx_sig]) < 0) {
+ return (-EINVAL);
+ }
+ /*
+ * This case (when trying to kill pid 0) just has a different errno
+ * returned in illumos than in Linux.
+ */
+ if (tgid == 0)
+ return (-ESRCH);
+ if (lx_lpid_to_spid(tgid, &s_pid) != 0)
+ return (-ESRCH);
+ if (SI_CANQUEUE(s_code)) {
+ return ((syscall(SYS_sigqueue, s_pid, sig,
+ lx_siginfo.lsi_value, s_code, 0) == -1) ?
+ (-errno): 0);
+ } else {
+ /*
+ * This case is unlikely, as the main entry point is through
+ * sigqueue, which always has a queuable si_code.
+ */
+ siginfo.si_signo = sig;
+ siginfo.si_code = s_code;
+ siginfo.si_pid = lx_siginfo.lsi_pid;
+ siginfo.si_value = lx_siginfo.lsi_value;
+ siginfo.si_uid = lx_siginfo.lsi_uid;
+ return ((syscall(SYS_brand, B_HELPER_SIGQUEUE,
+ tgid, sig, &siginfo)) ? (-errno) : 0);
+ }
+}
+
+/*
+ * Adds an additional argument for which thread within a thread group to send
+ * the signal to (added as the second argument).
+ */
+long
+lx_rt_tgsigqueueinfo(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
+{
+ pid_t tgid = (pid_t)p1;
+ pid_t tid = (pid_t)p2;
+ int lx_sig = (int)p3;
+ int sig;
+ lx_siginfo_t lx_siginfo;
+ siginfo_t siginfo;
+ int si_code;
+
+ if (uucopy((void *)p4, &lx_siginfo, sizeof (lx_siginfo_t)) != 0)
+ return (-EFAULT);
+ if (lx_sig < 0 || lx_sig > LX_NSIG || (sig = ltos_signo[lx_sig]) < 0) {
+ return (-EINVAL);
+ }
+ si_code = ltos_sigcode(lx_siginfo.lsi_code);
+ if (si_code == LX_SI_CODE_NOT_EXIST)
+ return (-EINVAL);
+ /*
+ * Check for invalid tgid and tids. That appears to be only negatives
+ * and 0 values. Everything else that doesn't exist is instead ESRCH.
+ */
+ if (tgid <= 0 || tid <= 0)
+ return (-EINVAL);
+ siginfo.si_signo = sig;
+ siginfo.si_code = si_code;
+ siginfo.si_pid = lx_siginfo.lsi_pid;
+ siginfo.si_value = lx_siginfo.lsi_value;
+ siginfo.si_uid = lx_siginfo.lsi_uid;
+
+ return ((syscall(SYS_brand, B_HELPER_TGSIGQUEUE, tgid, tid, sig,
+ &siginfo)) ? (-errno) : 0);
+}
+
+long
+lx_signalfd(int fd, uintptr_t mask, size_t msize)
+{
+ return (lx_signalfd4(fd, mask, msize, 0));
+}
+
+long
+lx_signalfd4(int fd, uintptr_t mask, size_t msize, int flags)
+{
+ sigset_t s_set;
+ int r;
+
+ if (msize != sizeof (int64_t))
+ return (-EINVAL);
+
+ if (ltos_sigset((lx_sigset_t *)mask, &s_set) != 0)
+ return (-errno);
+
+ r = signalfd(fd, &s_set, flags);
+
+ /*
+ * signalfd(3C) may fail with ENOENT if /dev/signalfd is not available.
+ * It is less jarring to Linux programs to tell them that internal
+ * allocation failed than to report an error number they are not
+ * expecting.
+ */
+ if (r == -1 && errno == ENOENT)
+ return (-ENODEV);
+
+ return (r == -1 ? -errno : r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/stack.c b/usr/src/lib/brand/lx/lx_brand/common/stack.c
new file mode 100644
index 0000000000..daa40f3cc6
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/stack.c
@@ -0,0 +1,338 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Manage the native/emulation stack for LX-branded LWPs.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+
+#include <thread.h>
+#include <sys/mman.h>
+#include <sys/brand.h>
+#include <sys/syscall.h>
+#include <sys/debug.h>
+
+#include <sys/lx_brand.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_thread.h>
+
+
+typedef struct lx_stack_list_ent {
+ thread_t sle_tid;
+ void *sle_stack;
+ size_t sle_stack_size;
+ lx_tsd_t *sle_tsd;
+} lx_stack_list_ent_t;
+
+static mutex_t lx_stack_list_lock = ERRORCHECKMUTEX;
+lx_stack_list_ent_t *lx_stack_list = NULL;
+unsigned int lx_stack_list_elems = 0;
+
+/*
+ * Usermode emulation alternate stack size, expressed as a page count:
+ */
+int lx_native_stack_page_count = LX_NATIVE_STACK_PAGE_COUNT;
+
+/*
+ * We use these private functions from libc to suspend signal delivery in
+ * critical sections:
+ */
+extern void _sigon(void);
+extern void _sigoff(void);
+
+void
+lx_stack_prefork(void)
+{
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ /*
+ * The "lx_stack_list_lock" mutex is used to protect access to the list
+ * of per-thread native stacks. Management of native stacks is
+ * generally performed while servicing an emulated fork(2), vfork(2) or
+ * clone(2) system call.
+ *
+ * Multiple threads may be attempting to create new threads or
+ * processes concurrently, but in the case of fork(2) only the
+ * currently executing thread is duplicated in the child process. We
+ * require that the stack list lock be taken before the native fork1()
+ * or forkx(), and released in both the parent and the child once the
+ * operation is complete. For vfork() the lock must only be released in
+ * the parent (once it resumes execution) since the child is borrowing
+ * the parent's thread. The _sigoff/_sigon dance will also only take
+ * place in the parent.
+ *
+ * Holding this mutex prevents the forked child from containing a
+ * copy-on-write copy of a locked mutex without the thread that would
+ * later unlock it. We also suspend signal delivery while entering
+ * this critical section to ensure async signal safety.
+ *
+ * Unfortunately some Linux applications (e.g. busybox) will call vfork
+ * and then call fork (without the expected intervening exec). We
+ * avoid the mutex deadlock by skipping the call since we know this
+ * thread has borrowed the parent's address space and the parent cannot
+ * execute until we exit/exec.
+ */
+ _sigoff();
+ if (lx_tsd->lxtsd_is_vforked == 0)
+ VERIFY0(mutex_lock(&lx_stack_list_lock));
+}
+
+void
+lx_stack_postfork(void)
+{
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ if (lx_tsd->lxtsd_is_vforked == 0)
+ VERIFY0(mutex_unlock(&lx_stack_list_lock));
+ _sigon();
+}
+
+/*
+ * Free the alternate stack for this thread.
+ */
+void
+lx_free_stack(void)
+{
+ thread_t me = thr_self();
+ int i;
+
+ _sigoff();
+ VERIFY0(mutex_lock(&lx_stack_list_lock));
+
+ /*
+ * Find this thread's stack in the list of stacks.
+ */
+ for (i = 0; i < lx_stack_list_elems; i++) {
+ if (lx_stack_list[i].sle_tid != me) {
+ continue;
+ }
+
+ (void) munmap(lx_stack_list[i].sle_stack,
+ lx_stack_list[i].sle_stack_size);
+
+ /*
+ * Free the thread-specific data structure for this thread.
+ */
+ if (lx_stack_list[i].sle_tsd != NULL) {
+ free(lx_stack_list[i].sle_tsd->lxtsd_clone_state);
+ free(lx_stack_list[i].sle_tsd);
+ }
+
+ /*
+ * Free up this stack list entry:
+ */
+ bzero(&lx_stack_list[i], sizeof (lx_stack_list[i]));
+
+ VERIFY0(mutex_unlock(&lx_stack_list_lock));
+ _sigon();
+ return;
+ }
+
+ /*
+ * Did not find the stack in the list.
+ */
+ assert(0);
+}
+
+/*
+ * After fork1(), we must unmap the stack of every thread other than the
+ * one copied into the child process.
+ */
+void
+lx_free_other_stacks(void)
+{
+ int i, this_stack = -1;
+ thread_t me = thr_self();
+ lx_tsd_t *lx_tsd = lx_get_tsd();
+
+ _sigoff();
+
+ /*
+ * We don't need to check or take the lx_stack_list_lock here because
+ * we are the only thread in this process, but if we got here via an
+ * evil vfork->fork path then we must drop the lock for the new child
+ * and reset our "is_vforked" counter.
+ */
+ if (lx_tsd->lxtsd_is_vforked != 0) {
+ VERIFY0(mutex_unlock(&lx_stack_list_lock));
+ lx_tsd->lxtsd_is_vforked = 0;
+ }
+
+ for (i = 0; i < lx_stack_list_elems; i++) {
+ if (lx_stack_list[i].sle_tid == me) {
+ /*
+ * Do not unmap the stack for this LWP.
+ */
+ this_stack = i;
+ continue;
+ } else if (lx_stack_list[i].sle_tid == 0) {
+ /*
+ * Skip any holes in the list.
+ */
+ continue;
+ }
+
+ /*
+ * Free the thread-specific data structure for this thread.
+ */
+ if (lx_stack_list[i].sle_tsd != NULL) {
+ free(lx_stack_list[i].sle_tsd->lxtsd_clone_state);
+ free(lx_stack_list[i].sle_tsd);
+ }
+
+ /*
+ * Unmap the stack of every other LWP.
+ */
+ (void) munmap(lx_stack_list[i].sle_stack,
+ lx_stack_list[i].sle_stack_size);
+ }
+ /*
+ * Did not find the stack for this LWP in the list.
+ */
+ assert(this_stack != -1);
+
+ /*
+ * Ensure the stack data for this LWP is in the first slot and shrink
+ * the list.
+ */
+ if (this_stack != 0) {
+ lx_stack_list[0] = lx_stack_list[this_stack];
+ }
+ lx_stack_list_elems = 1;
+ lx_stack_list = realloc(lx_stack_list, lx_stack_list_elems *
+ sizeof (lx_stack_list[0]));
+ if (lx_stack_list == NULL) {
+ lx_err_fatal("failed to shrink stack list: %s",
+ strerror(errno));
+ }
+
+ _sigon();
+}
+
+/*
+ * Allocate an alternate stack for the execution of native emulation routines.
+ * This routine is based, in part, on find_stack() from libc.
+ */
+int
+lx_alloc_stack(void **nstack, size_t *nstack_size)
+{
+ static int pagesize = 0;
+ static int stackprot = 0;
+ int stacksize = 0;
+ void *stack;
+
+ /*
+ * Fetch configuration once:
+ */
+ if (pagesize == 0) {
+ pagesize = _sysconf(_SC_PAGESIZE);
+ assert(pagesize > 0);
+ }
+ if (stackprot == 0) {
+ long lprot = _sysconf(_SC_STACK_PROT);
+
+ stackprot = lprot > 0 ? lprot : (PROT_READ | PROT_WRITE);
+ }
+
+ stacksize = lx_native_stack_page_count * pagesize;
+
+ if ((stack = mmap(NULL, stacksize, stackprot, MAP_PRIVATE |
+ MAP_NORESERVE | MAP_ANON, -1, (off_t)0)) == MAP_FAILED) {
+ int en = errno;
+ lx_debug("lx_alloc_stack: failed to allocate stack: %s",
+ strerror(errno));
+ errno = en;
+ return (-1);
+ }
+
+#if DEBUG
+ /*
+ * Write a recognisable pattern into the allocated stack pages.
+ */
+ for (pos = 0; pos < ((stacksize - 1) / 4); pos++) {
+ ((uint32_t *)stack)[pos] = 0x0facade0;
+ }
+#endif
+
+ *nstack = stack;
+ *nstack_size = stacksize;
+
+ return (0);
+}
+
+/*
+ * Configure the in-kernel brand-specific LWP data with the native stack
+ * pointer for this thread. If a stack is not passed, allocate one first.
+ */
+void
+lx_install_stack(void *stack, size_t stacksize, lx_tsd_t *tsd)
+{
+ thread_t me = thr_self();
+ int i;
+ uintptr_t stack_top;
+
+ if (stack == NULL) {
+ /*
+ * If we were not passed a stack, then allocate one:
+ */
+ if (lx_alloc_stack(&stack, &stacksize) == -1) {
+ lx_err_fatal("failed to allocate stack for thread "
+ "%d: %s", me, strerror(errno));
+ }
+ }
+
+ /*
+ * Install the stack in the global list of thread stacks.
+ */
+ _sigoff();
+ VERIFY0(mutex_lock(&lx_stack_list_lock));
+
+ for (i = 0; i < lx_stack_list_elems; i++) {
+ assert(lx_stack_list[i].sle_tid != me);
+ if (lx_stack_list[i].sle_tid == 0)
+ break;
+ }
+ if (i >= lx_stack_list_elems) {
+ lx_stack_list_elems++;
+ lx_stack_list = realloc(lx_stack_list, lx_stack_list_elems *
+ sizeof (lx_stack_list[0]));
+ if (lx_stack_list == NULL) {
+ lx_err_fatal("failed to extend stack list: %s",
+ strerror(errno));
+ }
+ }
+ lx_stack_list[i].sle_tid = me;
+ lx_stack_list[i].sle_stack = stack;
+ lx_stack_list[i].sle_stack_size = stacksize;
+ lx_stack_list[i].sle_tsd = tsd;
+
+ VERIFY0(mutex_unlock(&lx_stack_list_lock));
+ _sigon();
+
+ /*
+ * Inform the kernel of the location of the brand emulation
+ * stack for this LWP:
+ */
+ stack_top = (uintptr_t)stack + stacksize;
+ lx_debug("stack %p stack_top %p\n", stack, stack_top);
+ if (syscall(SYS_brand, B_SET_NATIVE_STACK, stack_top) != 0) {
+ lx_err_fatal("unable to set native stack: %s", strerror(errno));
+ }
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/statfs.c b/usr/src/lib/brand/lx/lx_brand/common/statfs.c
new file mode 100644
index 0000000000..629e549831
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/statfs.c
@@ -0,0 +1,348 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc. All rights reserved.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <sys/lx_debug.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_statfs.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * these defines must exist before we include regexp.h, see regexp(5)
+ */
+#define RE_SIZE 1024
+#define INIT char *sp = instring;
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(c) return (NULL);
+#define ERROR(c) return ((char *)c);
+
+/*
+ * for regular expressions we're using regexp(5).
+ *
+ * we'd really prefer to use some other nicer regular expressions
+ * interfaces (like regcmp(3c), regcomp(3c), or re_comp(3c)) but we
+ * can't because all these other interfaces rely on the ability
+ * to allocate memory via libc malloc()/calloc() calls, which
+ * we can't really do here.
+ *
+ * we could optionally use regexpr(3gen) but we don't since the
+ * interfaces there are incredibly similar to the regexp(5)
+ * interfaces we're already using and we'd have the added
+ * requirement of linking against libgen.
+ *
+ * another option that was considered is fnmatch(3c) but the
+ * limited pattern expansion capability of this interface would
+ * force us to include more patterns to check against.
+ */
+#include <regexp.h>
+
+static struct lx_ftype_path {
+ char *lfp_path;
+ char lfp_re[RE_SIZE];
+ int lfp_magic;
+ char *lfp_magic_str;
+} ftype_path_list[] = {
+ { "^/dev/pts$", "",
+ LX_DEVPTS_SUPER_MAGIC, "LX_DEVPTS_SUPER_MAGIC" },
+ { "^/dev/pts/$", "",
+ LX_DEVPTS_SUPER_MAGIC, "LX_DEVPTS_SUPER_MAGIC" },
+ { "^/dev/pts/[0-9][0-9]*$", "",
+ LX_DEVPTS_SUPER_MAGIC, "LX_DEVPTS_SUPER_MAGIC" },
+ { NULL, "",
+ 0, NULL }
+};
+
+/*
+ * For lack of linux equivalents, we present lofs and zfs as being ext2. Yes,
+ * this is a total lie, but Linux can't handle the truth of ZFS -- and ext2's
+ * small surface area seems to make it the most tenable lie to tell.
+ */
+static struct lx_ftype_name {
+ const char *lfn_name;
+ int lfn_magic;
+ char *lfn_magic_str;
+} ftype_name_list[] = {
+ { "hsfs", LX_ISOFS_SUPER_MAGIC, "LX_ISOFS_SUPER_MAGIC" },
+ { "nfs", LX_NFS_SUPER_MAGIC, "LX_NFS_SUPER_MAGIC" },
+ { "pcfs", LX_MSDOS_SUPER_MAGIC, "LX_MSDOS_SUPER_MAGIC" },
+ { "lx_proc", LX_PROC_SUPER_MAGIC, "LX_PROC_SUPER_MAGIC" },
+ { "tmpfs", LX_TMPFS_SUPER_MAGIC, "LX_TMPFS_SUPER_MAGIC" },
+ { "ufs", LX_UFS_MAGIC, "LX_UFS_MAGIC" },
+ { "lofs", LX_EXT2_SUPER_MAGIC, "LX_EXT2_SUPER_MAGIC" },
+ { "zfs", LX_EXT2_SUPER_MAGIC, "LX_EXT2_SUPER_MAGIC" },
+ { "lxautofs", LX_AUTOFS_SUPER_MAGIC, "LX_AUTOFS_SUPER_MAGIC" },
+ { "lx_cgroup", LX_CGROUP_SUPER_MAGIC, "LX_CGROUP_SUPER_MAGIC" },
+ { "lx_sysfs", LX_SYSFS_SUPER_MAGIC, "LX_SYSFS_SUPER_MAGIC" },
+ { NULL, 0, NULL }
+};
+
+int
+lx_statfs_init()
+{
+ int i;
+ char *rv;
+
+ for (i = 0; ftype_path_list[i].lfp_path != NULL; i++) {
+ rv = compile(
+ ftype_path_list[i].lfp_path,
+ ftype_path_list[i].lfp_re,
+ ftype_path_list[i].lfp_re + RE_SIZE, '\0');
+ if (rv == NULL)
+ continue;
+
+ lx_debug("lx_statfs_init compile(\"%s\") failed",
+ ftype_path_list[i].lfp_path);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+stol_type(const char *path, const char *name)
+{
+ int i;
+ lx_debug("\tstol_type(\"%s\", \"%s\")\n", path == NULL ? "NULL" : path,
+ name == NULL ? "NULL" : name);
+
+ if (path != NULL) {
+ char userpath[MAXPATHLEN];
+
+ if (uucopystr(path, userpath, MAXPATHLEN) == -1)
+ return (-errno);
+
+ for (i = 0; ftype_path_list[i].lfp_path != NULL; i++) {
+ if (step(userpath, ftype_path_list[i].lfp_re) == 0)
+ continue;
+
+ /* got a match on the fs path */
+ lx_debug("\ttranslated f_type to 0x%x - %s",
+ ftype_path_list[i].lfp_magic,
+ ftype_path_list[i].lfp_magic_str);
+ return (ftype_path_list[i].lfp_magic);
+ }
+ }
+
+ assert(name != NULL);
+ for (i = 0; ftype_name_list[i].lfn_name != NULL; i++) {
+ if (strcmp(name, ftype_name_list[i].lfn_name) == 0) {
+
+ /* got a match on the fs name */
+ lx_debug("\ttranslated f_type to 0x%x - %s",
+ ftype_name_list[i].lfn_magic,
+ ftype_name_list[i].lfn_magic_str);
+ return (ftype_name_list[i].lfn_magic);
+ }
+ }
+
+ /* we don't know what the fs type is so just set it to 0 */
+ return (0);
+}
+
+/*
+ * The Linux statfs() is similar to the Solaris statvfs() call, the main
+ * difference being the use of a numeric 'f_type' identifier instead of the
+ * 'f_basetype' string.
+ */
+static int
+stol_statfs(const char *path, struct lx_statfs *l, struct statvfs *s)
+{
+ int type;
+
+ if ((type = stol_type(path, s->f_basetype)) < 0)
+ return (type);
+
+ l->f_type = type;
+ l->f_bsize = s->f_frsize; /* other fields depend on frsize */
+ l->f_blocks = s->f_blocks;
+ l->f_bfree = s->f_bfree;
+ l->f_bavail = s->f_bavail;
+ l->f_files = s->f_files;
+ l->f_ffree = s->f_ffree;
+ l->f_fsid = s->f_fsid;
+ l->f_namelen = s->f_namemax;
+ l->f_frsize = s->f_frsize;
+ bzero(&(l->f_spare), sizeof (l->f_spare));
+
+ return (0);
+}
+
+static int
+stol_statfs64(const char *path, struct lx_statfs64 *l, struct statvfs64 *s)
+{
+ int type;
+
+ if ((type = stol_type(path, s->f_basetype)) < 0)
+ return (type);
+
+ l->f_type = type;
+ l->f_bsize = s->f_frsize; /* other fields depend on frsize */
+ l->f_blocks = s->f_blocks;
+ l->f_bfree = s->f_bfree;
+ l->f_bavail = s->f_bavail;
+ l->f_files = s->f_files;
+ l->f_ffree = s->f_ffree;
+ l->f_fsid = s->f_fsid;
+ l->f_namelen = s->f_namemax;
+ l->f_frsize = s->f_frsize;
+ bzero(&(l->f_spare), sizeof (l->f_spare));
+
+ return (0);
+}
+
+long
+lx_statfs(uintptr_t p1, uintptr_t p2)
+{
+ const char *path = (const char *)p1;
+ struct lx_statfs lxfs, *fs = (struct lx_statfs *)p2;
+ struct statvfs vfs;
+ int err;
+
+ lx_debug("\tstatvfs(%s, 0x%p)", path, fs);
+ if (statvfs(path, &vfs) != 0)
+ return (-errno);
+
+ if ((err = stol_statfs(path, &lxfs, &vfs)) != 0)
+ return (err);
+
+ if (uucopy(&lxfs, fs, sizeof (struct lx_statfs)) != 0)
+ return (-errno);
+
+ return (0);
+}
+
+long
+lx_fstatfs(uintptr_t p1, uintptr_t p2)
+{
+ struct lx_statfs lxfs, *fs = (struct lx_statfs *)p2;
+ struct stat64 sb;
+ struct statvfs vfs;
+ char *path, path_buf[MAXPATHLEN];
+ int fd = (int)p1;
+ int err;
+
+ lx_debug("\tfstatvfs(%d, 0x%p)", fd, fs);
+
+ /*
+ * fstatfs emulation for a pipe.
+ */
+ if (fstat64(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
+ lxfs.f_type = LX_PIPEFS_MAGIC;
+ lxfs.f_bsize = 4096;
+ lxfs.f_blocks = 0;
+ lxfs.f_bfree = 0;
+ lxfs.f_bavail = 0;
+ lxfs.f_files = 0;
+ lxfs.f_ffree = 0;
+ lxfs.f_fsid = 0;
+ lxfs.f_namelen = 255;
+ lxfs.f_frsize = 4096;
+ } else {
+ if (fstatvfs(fd, &vfs) != 0)
+ return (-errno);
+
+ path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
+
+ if ((err = stol_statfs(path, &lxfs, &vfs)) != 0)
+ return (err);
+ }
+
+ if (uucopy(&lxfs, fs, sizeof (struct lx_statfs)) != 0)
+ return (-errno);
+
+ return (0);
+}
+
+/* ARGSUSED */
+long
+lx_statfs64(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ const char *path = (const char *)p1;
+ struct lx_statfs64 lxfs, *fs = (struct lx_statfs64 *)p3;
+ struct statvfs64 vfs;
+ int err;
+
+ lx_debug("\tstatvfs64(%s, %d, 0x%p)", path, p2, fs);
+ if (statvfs64(path, &vfs) != 0)
+ return (-errno);
+
+ if ((err = stol_statfs64(path, &lxfs, &vfs)) != 0)
+ return (err);
+
+ if (uucopy(&lxfs, fs, sizeof (struct lx_statfs64)) != 0)
+ return (-errno);
+
+ return (0);
+}
+
+/* ARGSUSED */
+long
+lx_fstatfs64(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ struct lx_statfs64 lxfs, *fs = (struct lx_statfs64 *)p3;
+ struct stat64 sb;
+ struct statvfs64 vfs;
+ char *path, path_buf[MAXPATHLEN];
+ int fd = (int)p1;
+ int err;
+
+ lx_debug("\tfstatvfs64(%d, %d, 0x%p)", fd, p2, fs);
+ if (fstat64(fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
+ lxfs.f_type = LX_PIPEFS_MAGIC;
+ lxfs.f_bsize = 4096;
+ lxfs.f_blocks = 0;
+ lxfs.f_bfree = 0;
+ lxfs.f_bavail = 0;
+ lxfs.f_files = 0;
+ lxfs.f_ffree = 0;
+ lxfs.f_fsid = 0;
+ lxfs.f_namelen = 255;
+ lxfs.f_frsize = 4096;
+ } else {
+ if (fstatvfs64(fd, &vfs) != 0)
+ return (-errno);
+
+ path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
+
+ if ((err = stol_statfs64(path, &lxfs, &vfs)) != 0)
+ return (err);
+ }
+
+ if (uucopy(&lxfs, fs, sizeof (struct lx_statfs64)) != 0)
+ return (-errno);
+
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/sysctl.c b/usr/src/lib/brand/lx/lx_brand/common/sysctl.c
new file mode 100644
index 0000000000..262a9c3830
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/sysctl.c
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_debug.h>
+
+/*
+ * sysctl() implementation. The full set of possible values is incredibly
+ * large; we only implement the bare minimum here, namely basic kernel
+ * information.
+ *
+ * For the moment, we also print out debugging messages if the application
+ * attempts to write or access any other values, so we can tell if we are not
+ * supporting something we should be.
+ */
+
+struct lx_sysctl_args {
+ int *name;
+ int nlen;
+ void *oldval;
+ size_t *oldlenp;
+ void *newval;
+ size_t newlen;
+};
+
+#define LX_CTL_KERN 1
+
+#define LX_KERN_OSTYPE 1
+#define LX_KERN_OSRELEASE 2
+#define LX_KERN_OSREV 3
+#define LX_KERN_VERSION 4
+
+long
+lx_sysctl(uintptr_t raw)
+{
+ struct lx_sysctl_args args;
+ int name[2];
+ size_t oldlen;
+ char *namebuf;
+
+ if (uucopy((void *)raw, &args, sizeof (args)) < 0)
+ return (-EFAULT);
+
+ /*
+ * We only allow [ CTL_KERN, KERN_* ] pairs, so reject anything that
+ * doesn't have exactly two values starting with LX_CTL_KERN.
+ */
+ if (args.nlen != 2)
+ return (-ENOTDIR);
+
+ if (uucopy(args.name, name, sizeof (name)) < 0)
+ return (-EFAULT);
+
+ if (name[0] != LX_CTL_KERN) {
+ lx_debug("sysctl: read of [%d, %d] unsupported",
+ name[0], name[1]);
+ return (-ENOTDIR);
+ }
+
+ /* We don't support writing new sysctl values. */
+ if ((args.newval != NULL) || (args.newlen != 0)) {
+ lx_debug("sysctl: write of [%d, %d] unsupported",
+ name[0], name[1]);
+ return (-EPERM);
+ }
+
+ /*
+ * It may seem silly, but passing in a NULL oldval pointer and not
+ * writing any new values is a perfectly legal thing to do and should
+ * succeed.
+ */
+ if (args.oldval == NULL)
+ return (0);
+
+ /*
+ * Likewise, Linux specifies that setting a non-NULL oldval but a
+ * zero *oldlenp should result in an errno of EFAULT.
+ */
+ if ((uucopy(args.oldlenp, &oldlen, sizeof (oldlen)) < 0) ||
+ (oldlen == 0))
+ return (-EFAULT);
+
+ namebuf = SAFE_ALLOCA(oldlen);
+ if (namebuf == NULL)
+ return (-ENOMEM);
+
+ switch (name[1]) {
+ case LX_KERN_OSTYPE:
+ (void) strlcpy(namebuf, LX_UNAME_SYSNAME, oldlen);
+ break;
+ case LX_KERN_OSRELEASE:
+ (void) strlcpy(namebuf, lx_release, oldlen);
+ break;
+ case LX_KERN_VERSION:
+ (void) strlcpy(namebuf, LX_UNAME_VERSION, oldlen);
+ break;
+ default:
+ lx_debug("sysctl: read of [CTL_KERN, %d] unsupported", name[1]);
+ return (-ENOTDIR);
+ }
+
+ oldlen = strlen(namebuf);
+
+ if ((uucopy(namebuf, args.oldval, oldlen) < 0) ||
+ (uucopy(&oldlen, args.oldlenp, sizeof (oldlen)) < 0))
+ return (-EFAULT);
+
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/sysv_ipc.c b/usr/src/lib/brand/lx/lx_brand/common/sysv_ipc.c
new file mode 100644
index 0000000000..aa4f4ffb40
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/sysv_ipc.c
@@ -0,0 +1,987 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <strings.h>
+#include <rctl.h>
+#include <alloca.h>
+#include <values.h>
+#include <sys/syscall.h>
+#include <sys/msg.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/lx_debug.h>
+#include <sys/lx_types.h>
+#include <sys/lx_sysv_ipc.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+#define SLOT_SEM 0
+#define SLOT_SHM 1
+#define SLOT_MSG 2
+
+/* Use private SHM_RMID interface for IPC_RMID */
+#define SHM_RMID 5
+
+static int
+get_rctlval(rctlblk_t *rblk, char *name, ulong_t limit, uint64_t *val)
+{
+ rctl_qty_t r;
+
+ if (getrctl(name, NULL, rblk, RCTL_FIRST) == -1)
+ return (-errno);
+
+ r = rctlblk_get_value(rblk);
+ if (r > limit)
+ return (-EOVERFLOW);
+
+ *val = r;
+ return (0);
+}
+
+/*
+ * Given a slot number and a maximum number of ids to extract from the
+ * kernel, return the msgid in the provided slot.
+ */
+static int
+slot_to_id(int type, int slot)
+{
+ uint_t nids, max;
+ int *idbuf = NULL;
+ int r = 0;
+
+ nids = 0;
+ for (;;) {
+ switch (type) {
+ case SLOT_SEM:
+ r = semids(idbuf, nids, &max);
+ break;
+ case SLOT_SHM:
+ r = shmids(idbuf, nids, &max);
+ break;
+ case SLOT_MSG:
+ r = msgids(idbuf, nids, &max);
+ break;
+ }
+
+ if (r < 0)
+ return (-errno);
+
+ if (max == 0)
+ return (-EINVAL);
+
+ if (max <= nids)
+ return (idbuf[slot]);
+
+ nids = max;
+ if ((idbuf = (int *)SAFE_ALLOCA(sizeof (int) * nids)) == NULL)
+ return (-ENOMEM);
+ }
+}
+
+/*
+ * Semaphore operations.
+ */
+long
+lx_semget(key_t key, int nsems, int semflg)
+{
+ int sol_flag;
+ int r;
+
+ lx_debug("\nsemget(%d, %d, %d)\n", key, nsems, semflg);
+ sol_flag = semflg & S_IAMB;
+ if (semflg & LX_IPC_CREAT)
+ sol_flag |= IPC_CREAT;
+ if (semflg & LX_IPC_EXCL)
+ sol_flag |= IPC_EXCL;
+
+ r = semget(key, nsems, sol_flag);
+ return ((r < 0) ? -errno : r);
+}
+
+long
+lx_semop(int semid, void *p1, size_t nsops)
+{
+ int r;
+ struct sembuf *sops = (struct sembuf *)p1;
+
+ lx_debug("\nsemop(%d, 0x%p, %u)\n", semid, sops, nsops);
+ if (nsops == 0)
+ return (-EINVAL);
+
+ r = semop(semid, sops, nsops);
+ return ((r < 0) ? -errno : r);
+}
+
+long
+lx_semtimedop(int semid, void *p1, size_t nsops, struct timespec *timeout)
+{
+ int r;
+ struct sembuf *sops = (struct sembuf *)p1;
+
+ lx_debug("\nsemtimedop(%d, 0x%p, %u, 0x%p)\n", semid, sops, nsops,
+ timeout);
+ if (nsops == 0)
+ return (-EINVAL);
+
+ r = semtimedop(semid, sops, nsops, timeout);
+ return ((r < 0) ? -errno : r);
+}
+
+static int
+lx_semctl_ipcset(int semid, void *buf)
+{
+ struct lx_semid_ds semds;
+ struct semid_ds sol_semds;
+ int r;
+
+ if (uucopy(buf, &semds, sizeof (semds)))
+ return (-errno);
+
+ bzero(&sol_semds, sizeof (sol_semds));
+ sol_semds.sem_perm.uid = semds.sem_perm.uid;
+ sol_semds.sem_perm.gid = semds.sem_perm.gid;
+ sol_semds.sem_perm.mode = semds.sem_perm.mode;
+
+ r = semctl(semid, 0, IPC_SET, &sol_semds);
+ return ((r < 0) ? -errno : r);
+}
+
+static int
+lx_semctl_ipcstat(int semid, void *buf)
+{
+ struct lx_semid_ds semds;
+ struct semid_ds sol_semds;
+
+ if (semctl(semid, 0, IPC_STAT, &sol_semds) != 0)
+ return (-errno);
+
+ bzero(&semds, sizeof (semds));
+ semds.sem_perm.key = sol_semds.sem_perm.key;
+ semds.sem_perm.seq = sol_semds.sem_perm.seq;
+ semds.sem_perm.uid = sol_semds.sem_perm.uid;
+ semds.sem_perm.gid = sol_semds.sem_perm.gid;
+ semds.sem_perm.cuid = sol_semds.sem_perm.cuid;
+ semds.sem_perm.cgid = sol_semds.sem_perm.cgid;
+
+ /* Linux only uses the bottom 9 bits */
+ semds.sem_perm.mode = sol_semds.sem_perm.mode & S_IAMB;
+ semds.sem_otime = sol_semds.sem_otime;
+ semds.sem_ctime = sol_semds.sem_ctime;
+ semds.sem_nsems = sol_semds.sem_nsems;
+
+ if (uucopy(&semds, buf, sizeof (semds)))
+ return (-errno);
+
+ return (0);
+}
+
+static int
+lx_semctl_ipcinfo(void *buf)
+{
+ struct lx_seminfo i;
+ rctlblk_t *rblk;
+ int rblksz;
+ uint_t nids;
+ int idbuf;
+ int err;
+ uint64_t val;
+
+ rblksz = rctlblk_size();
+ if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
+ return (-ENOMEM);
+
+ bzero(&i, sizeof (i));
+ err = get_rctlval(rblk, "project.max-sem-ids", (ulong_t)MAXINT, &val);
+ if (err < 0)
+ return (err);
+ i.semmni = (int)val;
+ err = get_rctlval(rblk, "process.max-sem-nsems", (ulong_t)MAXINT, &val);
+ if (err < 0)
+ return (err);
+ i.semmsl = (int)val;
+ err = get_rctlval(rblk, "process.max-sem-ops", (ulong_t)MAXINT, &val);
+ if (err < 0)
+ return (err);
+ i.semopm = (int)val;
+
+ /*
+ * We don't have corresponding rctls for these fields. The values
+ * are taken from the formulas used to derive the defaults listed
+ * in the Linux header file. We're lying, but trying to be
+ * coherent about it.
+ */
+ i.semmap = i.semmni;
+ i.semmns = i.semmni * i.semmsl;
+ i.semmnu = INT_MAX;
+ i.semume = INT_MAX;
+ i.semvmx = LX_SEMVMX;
+ if (semids(&idbuf, 0, &nids) < 0)
+ return (-errno);
+ i.semusz = nids;
+ i.semaem = INT_MAX;
+
+ if (uucopy(&i, buf, sizeof (i)) != 0)
+ return (-errno);
+
+ return (nids);
+}
+
+static int
+lx_semctl_semstat(int slot, void *buf)
+{
+ int r, semid;
+
+ semid = slot_to_id(SLOT_SEM, slot);
+ if (semid < 0)
+ return (semid);
+
+ r = lx_semctl_ipcstat(semid, buf);
+ return (r < 0 ? r : semid);
+}
+
+/*
+ * For the SETALL operation, we have to examine each of the semaphore
+ * values to be sure it is legal.
+ */
+static int
+lx_semctl_setall(int semid, ushort_t *arg)
+{
+ struct semid_ds semds;
+ ushort_t *vals;
+ int i, sz, r;
+
+ /*
+ * Find out how many semaphores are involved, reserve enough
+ * memory for an internal copy of the array, and then copy it in
+ * from the process.
+ */
+ if (semctl(semid, 0, IPC_STAT, &semds) != 0)
+ return (-errno);
+ sz = semds.sem_nsems * sizeof (ushort_t);
+ if ((vals = SAFE_ALLOCA(sz)) == NULL)
+ return (-ENOMEM);
+ if (uucopy(arg, vals, sz))
+ return (-errno);
+
+ /* Validate each of the values. */
+ for (i = 0; i < semds.sem_nsems; i++)
+ if (vals[i] > LX_SEMVMX)
+ return (-ERANGE);
+
+ r = semctl(semid, 0, SETALL, arg);
+
+ return ((r < 0) ? -errno : r);
+}
+
+long
+lx_semctl(int semid, int semnum, int cmd, void *ptr)
+{
+#if defined(_ILP32)
+ union lx_semun arg;
+#endif
+ int rval;
+ int opt = cmd & ~LX_IPC_64;
+ int use_errno = 0;
+ uint_t val;
+
+ lx_debug("\nsemctl(%d, %d, %d, 0x%p)\n", semid, semnum, cmd, ptr);
+
+#if defined(_ILP32)
+ /*
+ * The final arg to semctl() is a pointer to a union. For some
+ * commands we can hand that pointer directly to the kernel. For
+ * these commands, we need to extract an argument from the union
+ * before calling into the kernel.
+ */
+ if (opt == LX_SETVAL || opt == LX_SETALL || opt == LX_GETALL ||
+ opt == LX_IPC_SET || opt == LX_IPC_STAT || opt == LX_SEM_STAT ||
+ opt == LX_IPC_INFO || opt == LX_SEM_INFO)
+ if (uucopy(ptr, &arg, sizeof (arg)))
+ return (-errno);
+#endif
+
+ switch (opt) {
+ case LX_GETVAL:
+ use_errno = 1;
+ rval = semctl(semid, semnum, GETVAL, NULL);
+ break;
+ case LX_SETVAL:
+#if defined(_ILP32)
+ val = arg.val;
+#else
+ val = (uint_t)(uintptr_t)ptr;
+#endif
+ if (val > LX_SEMVMX) {
+ return (-ERANGE);
+ }
+ use_errno = 1;
+ rval = semctl(semid, semnum, SETVAL, val);
+ break;
+ case LX_GETPID:
+ use_errno = 1;
+ rval = semctl(semid, semnum, GETPID, NULL);
+ break;
+ case LX_GETNCNT:
+ use_errno = 1;
+ rval = semctl(semid, semnum, GETNCNT, NULL);
+ break;
+ case LX_GETZCNT:
+ use_errno = 1;
+ rval = semctl(semid, semnum, GETZCNT, NULL);
+ break;
+ case LX_GETALL:
+ use_errno = 1;
+#if defined(_ILP32)
+ rval = semctl(semid, semnum, GETALL, arg.sems);
+#else
+ rval = semctl(semid, semnum, GETALL, ptr);
+#endif
+ break;
+ case LX_SETALL:
+#if defined(_ILP32)
+ rval = lx_semctl_setall(semid, arg.sems);
+#else
+ rval = lx_semctl_setall(semid, ptr);
+#endif
+ break;
+ case LX_IPC_RMID:
+ use_errno = 1;
+ rval = semctl(semid, semnum, IPC_RMID, NULL);
+ break;
+ case LX_SEM_STAT:
+#if defined(_ILP32)
+ rval = lx_semctl_semstat(semid, arg.semds);
+#else
+ rval = lx_semctl_semstat(semid, ptr);
+#endif
+ break;
+ case LX_IPC_STAT:
+#if defined(_ILP32)
+ rval = lx_semctl_ipcstat(semid, arg.semds);
+#else
+ rval = lx_semctl_ipcstat(semid, ptr);
+#endif
+ break;
+
+ case LX_IPC_SET:
+#if defined(_ILP32)
+ rval = lx_semctl_ipcset(semid, arg.semds);
+#else
+ rval = lx_semctl_ipcset(semid, ptr);
+#endif
+ break;
+
+ case LX_IPC_INFO:
+ case LX_SEM_INFO:
+#if defined(_ILP32)
+ rval = lx_semctl_ipcinfo(arg.semds);
+#else
+ rval = lx_semctl_ipcinfo(ptr);
+#endif
+ break;
+
+ default:
+ return (-EINVAL);
+ }
+
+ if (use_errno == 1 && rval < 0)
+ return (-errno);
+ return (rval);
+}
+
+/*
+ * msg operations.
+ */
+long
+lx_msgget(key_t key, int flag)
+{
+ int sol_flag;
+ int r;
+
+ lx_debug("\tlx_msgget(%d, %d)\n", key, flag);
+
+ sol_flag = flag & S_IAMB;
+ if (flag & LX_IPC_CREAT)
+ sol_flag |= IPC_CREAT;
+ if (flag & LX_IPC_EXCL)
+ sol_flag |= IPC_EXCL;
+
+ r = msgget(key, sol_flag);
+ return (r < 0 ? -errno : r);
+}
+
+long
+lx_msgsnd(int id, void *p1, size_t sz, int flag)
+{
+ int sol_flag = 0;
+ int r;
+ struct msgbuf *buf = (struct msgbuf *)p1;
+
+ lx_debug("\tlx_msgsnd(%d, 0x%p, %d, %d)\n", id, buf, sz, flag);
+
+ if (flag & LX_IPC_NOWAIT)
+ sol_flag |= IPC_NOWAIT;
+
+ if (((ssize_t)sz < 0) || (sz > LX_MSGMAX))
+ return (-EINVAL);
+
+ r = msgsnd(id, buf, sz, sol_flag);
+ return (r < 0 ? -errno : r);
+}
+
+long
+lx_msgrcv(int id, void *msgp, size_t sz, long msgtype, int flag)
+{
+ int sol_flag = 0;
+ ssize_t r;
+
+ lx_debug("\tlx_msgrcv(%d, 0x%p, %d, %d, %ld, %d)\n",
+ id, msgp, sz, msgtype, flag);
+
+ /*
+ * Check for a negative sz parameter.
+ *
+ * Unlike msgsnd(2), the Linux man page does not specify that
+ * msgrcv(2) should return EINVAL if (sz > MSGMAX), only if (sz < 0).
+ */
+ if ((ssize_t)sz < 0)
+ return (-EINVAL);
+
+ if (flag & LX_MSG_NOERROR)
+ sol_flag |= MSG_NOERROR;
+ if (flag & LX_IPC_NOWAIT)
+ sol_flag |= IPC_NOWAIT;
+
+ r = msgrcv(id, msgp, sz, msgtype, sol_flag);
+ return (r < 0 ? -errno : r);
+}
+
+static int
+lx_msgctl_ipcstat(int msgid, void *buf)
+{
+ struct lx_msqid_ds msgids;
+ struct msqid_ds sol_msgids;
+ int r;
+
+ r = msgctl(msgid, IPC_STAT, &sol_msgids);
+ if (r < 0)
+ return (-errno);
+
+ bzero(&msgids, sizeof (msgids));
+ msgids.msg_perm.key = sol_msgids.msg_perm.key;
+ msgids.msg_perm.seq = sol_msgids.msg_perm.seq;
+ msgids.msg_perm.uid = sol_msgids.msg_perm.uid;
+ msgids.msg_perm.gid = sol_msgids.msg_perm.gid;
+ msgids.msg_perm.cuid = sol_msgids.msg_perm.cuid;
+ msgids.msg_perm.cgid = sol_msgids.msg_perm.cgid;
+
+ /* Linux only uses the bottom 9 bits */
+ msgids.msg_perm.mode = sol_msgids.msg_perm.mode & S_IAMB;
+
+ msgids.msg_stime = sol_msgids.msg_stime;
+ msgids.msg_rtime = sol_msgids.msg_rtime;
+ msgids.msg_ctime = sol_msgids.msg_ctime;
+ msgids.msg_qbytes = sol_msgids.msg_qbytes;
+ msgids.msg_cbytes = sol_msgids.msg_cbytes;
+ msgids.msg_qnum = sol_msgids.msg_qnum;
+ msgids.msg_lspid = sol_msgids.msg_lspid;
+ msgids.msg_lrpid = sol_msgids.msg_lrpid;
+
+ if (uucopy(&msgids, buf, sizeof (msgids)))
+ return (-errno);
+
+ return (0);
+}
+
+static int
+lx_msgctl_ipcinfo(int cmd, void *buf)
+{
+ struct lx_msginfo m;
+ rctlblk_t *rblk;
+ int idbuf, rblksz, msgseg, maxmsgs;
+ uint_t nids;
+ int rval;
+ int err;
+ uint64_t val;
+
+ rblksz = rctlblk_size();
+ if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
+ return (-ENOMEM);
+
+ bzero(&m, sizeof (m));
+ err = get_rctlval(rblk, "project.max-msg-ids", (ulong_t)MAXINT, &val);
+ if (err < 0)
+ return (err);
+ m.msgmni = (int)val;
+ err = get_rctlval(rblk, "process.max-msg-qbytes", (ulong_t)MAXINT,
+ &val);
+ if (err < 0)
+ return (err);
+ m.msgmnb = (int)val;
+
+ if (cmd == LX_IPC_INFO) {
+ err = get_rctlval(rblk, "process.max-msg-messages",
+ (ulong_t)MAXINT, &val);
+ if (err < 0)
+ return (err);
+ maxmsgs = (int)val;
+ m.msgtql = maxmsgs * m.msgmni;
+ m.msgmap = m.msgmnb;
+ m.msgpool = m.msgmax * m.msgmnb;
+ rval = 0;
+ } else {
+ if (msgids(&idbuf, 0, &nids) < 0)
+ return (-errno);
+ m.msgpool = nids;
+
+ /*
+ * For these fields, we can't even come up with a good fake
+ * approximation. These are listed as 'obsolete' or
+ * 'unused' in the header files, so hopefully nobody is
+ * relying on them anyway.
+ */
+ m.msgtql = INT_MAX;
+ m.msgmap = INT_MAX;
+ rval = nids;
+ }
+
+ /*
+ * We don't have corresponding rctls for these fields. The values
+ * are taken from the formulas used to derive the defaults listed
+ * in the Linux header file. We're lying, but trying to be
+ * coherent about it.
+ */
+ m.msgmax = LX_MSGMAX;
+ m.msgssz = 16;
+ msgseg = (m.msgpool * 1024) / m.msgssz;
+ m.msgseg = (msgseg > 0xffff) ? 0xffff : msgseg;
+
+ if (uucopy(&m, buf, sizeof (m)))
+ return (-errno);
+ return (rval);
+}
+
+static int
+lx_msgctl_ipcset(int msgid, void *buf)
+{
+ struct lx_msqid_ds msgids;
+ struct msqid_ds sol_msgids;
+ int r;
+
+ if (uucopy(buf, &msgids, sizeof (msgids)))
+ return (-errno);
+
+ bzero(&sol_msgids, sizeof (sol_msgids));
+ sol_msgids.msg_perm.uid = LX_UID16_TO_UID32(msgids.msg_perm.uid);
+ sol_msgids.msg_perm.gid = LX_UID16_TO_UID32(msgids.msg_perm.gid);
+
+ /* Linux only uses the bottom 9 bits */
+ sol_msgids.msg_perm.mode = msgids.msg_perm.mode & S_IAMB;
+ sol_msgids.msg_qbytes = msgids.msg_qbytes;
+
+ r = msgctl(msgid, IPC_SET, &sol_msgids);
+ return (r < 0 ? -errno : r);
+}
+
+static int
+lx_msgctl_msgstat(int slot, void *buf)
+{
+ int r, msgid;
+
+ lx_debug("msgstat(%d, 0x%p)\n", slot, buf);
+
+ msgid = slot_to_id(SLOT_MSG, slot);
+
+ if (msgid < 0)
+ return (msgid);
+
+ r = lx_msgctl_ipcstat(msgid, buf);
+ return (r < 0 ? r : msgid);
+}
+
+/*
+ * Split off the various msgctl's here
+ */
+long
+lx_msgctl(int msgid, int cmd, void *buf)
+{
+ int r;
+
+ lx_debug("\tlx_msgctl(%d, %d, 0x%p)\n", msgid, cmd, buf);
+ switch (cmd & ~LX_IPC_64) {
+ case LX_IPC_RMID:
+ r = msgctl(msgid, IPC_RMID, NULL);
+ if (r < 0)
+ r = -errno;
+ break;
+ case LX_IPC_SET:
+ r = lx_msgctl_ipcset(msgid, buf);
+ break;
+ case LX_IPC_STAT:
+ r = lx_msgctl_ipcstat(msgid, buf);
+ break;
+ case LX_MSG_STAT:
+ r = lx_msgctl_msgstat(msgid, buf);
+ break;
+
+ case LX_IPC_INFO:
+ case LX_MSG_INFO:
+ r = lx_msgctl_ipcinfo(cmd, buf);
+ break;
+
+ default:
+ r = -EINVAL;
+ break;
+ }
+
+ return (r);
+}
+
+/*
+ * shm-related operations.
+ */
+long
+lx_shmget(key_t key, size_t size, int flag)
+{
+ int sol_flag;
+ int r;
+
+ lx_debug("\tlx_shmget(%d, %d, %d)\n", key, size, flag);
+
+ sol_flag = flag & S_IAMB;
+ if (flag & LX_IPC_CREAT)
+ sol_flag |= IPC_CREAT;
+ if (flag & LX_IPC_EXCL)
+ sol_flag |= IPC_EXCL;
+
+ r = shmget(key, size, sol_flag);
+ return (r < 0 ? -errno : r);
+}
+
+long
+lx_shmat(int shmid, void *addr, int flags)
+{
+ int sol_flags;
+ void *ptr;
+
+ lx_debug("\tlx_shmat(%d, 0x%p, %d)\n", shmid, addr, flags);
+
+ /*
+ * Linux has a fix for CVE-2017-5669 which LTP is testing for. The
+ * kernel will disallow mapping into the first 64k of the address space.
+ * LTP passes 1 as the address which will then round down to 0.
+ * In the future, once more work has been done to tighten up the lx
+ * brand handling for the minimum mappable address (e.g. with secflags),
+ * then we can remove this check.
+ */
+ if ((flags & LX_SHM_RND) && addr != NULL && addr < (void *)0x10000) {
+ return (-EINVAL);
+ }
+
+ sol_flags = 0;
+ if (flags & LX_SHM_RDONLY)
+ sol_flags |= SHM_RDONLY;
+ if (flags & LX_SHM_RND)
+ sol_flags |= SHM_RND;
+ if ((flags & LX_SHM_REMAP) && (addr == NULL))
+ return (-EINVAL);
+
+ ptr = shmat(shmid, addr, sol_flags);
+ if (ptr == (void *)-1)
+ return (-errno);
+
+ return ((ssize_t)ptr);
+}
+
+static int
+lx_shmctl_ipcinfo(void *buf)
+{
+ struct lx_shminfo s;
+ rctlblk_t *rblk;
+ int rblksz;
+ int err;
+ uint64_t val;
+
+ rblksz = rctlblk_size();
+ if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
+ return (-ENOMEM);
+
+ bzero(&s, sizeof (s));
+ err = get_rctlval(rblk, "project.max-shm-ids", ULONG_MAX, &val);
+ if (err < 0)
+ return (err);
+ s.shmmni = val;
+ err = get_rctlval(rblk, "project.max-shm-memory", ULONG_MAX, &val);
+ if (err < 0)
+ return (err);
+ s.shmmax = val;
+
+ /*
+ * We don't have corresponding rctls for these fields. The values
+ * are taken from the formulas used to derive the defaults listed
+ * in the Linux header file. We're lying, but trying to be
+ * coherent about it.
+ */
+ s.shmmin = 1;
+ s.shmseg = ULONG_MAX;
+ s.shmall = s.shmmax / getpagesize();
+
+ if (uucopy(&s, buf, sizeof (s)))
+ return (-errno);
+
+ return (0);
+}
+
+static int
+lx_shmctl_ipcstat(int shmid, void *buf)
+{
+ struct lx_shmid_ds shmds;
+ struct shmid_ds sol_shmds;
+
+ if (shmctl(shmid, IPC_STAT, &sol_shmds) != 0)
+ return (-errno);
+
+ bzero(&shmds, sizeof (shmds));
+ shmds.shm_perm.key = sol_shmds.shm_perm.key;
+ shmds.shm_perm.seq = sol_shmds.shm_perm.seq;
+ shmds.shm_perm.uid = sol_shmds.shm_perm.uid;
+ shmds.shm_perm.gid = sol_shmds.shm_perm.gid;
+ shmds.shm_perm.cuid = sol_shmds.shm_perm.cuid;
+ shmds.shm_perm.cgid = sol_shmds.shm_perm.cgid;
+ shmds.shm_perm.mode = sol_shmds.shm_perm.mode & S_IAMB;
+ if (sol_shmds.shm_lkcnt > 0)
+ shmds.shm_perm.mode |= LX_SHM_LOCKED;
+ shmds.shm_segsz = sol_shmds.shm_segsz;
+ shmds.shm_atime = sol_shmds.shm_atime;
+ shmds.shm_dtime = sol_shmds.shm_dtime;
+ shmds.shm_ctime = sol_shmds.shm_ctime;
+ shmds.shm_cpid = sol_shmds.shm_cpid;
+ shmds.shm_lpid = sol_shmds.shm_lpid;
+ shmds.shm_nattch = (ushort_t)sol_shmds.shm_nattch;
+
+ if (uucopy(&shmds, buf, sizeof (shmds)))
+ return (-errno);
+
+ return (0);
+}
+
+static int
+lx_shmctl_ipcset(int shmid, void *buf)
+{
+ struct lx_shmid_ds shmds;
+ struct shmid_ds sol_shmds;
+ int r;
+
+ if (uucopy(buf, &shmds, sizeof (shmds)))
+ return (-errno);
+
+ bzero(&sol_shmds, sizeof (sol_shmds));
+ sol_shmds.shm_perm.uid = shmds.shm_perm.uid;
+ sol_shmds.shm_perm.gid = shmds.shm_perm.gid;
+ sol_shmds.shm_perm.mode = shmds.shm_perm.mode & S_IAMB;
+
+ r = shmctl(shmid, IPC_SET, &sol_shmds);
+ return (r < 0 ? -errno : r);
+}
+
+/*
+ * Build and return a shm_info structure. We only return the bare
+ * essentials required by ipcs. The rest of the info is not readily
+ * available.
+ */
+static int
+lx_shmctl_shminfo(void *buf)
+{
+ struct lx_shm_info shminfo;
+ uint_t nids;
+ int idbuf;
+
+ bzero(&shminfo, sizeof (shminfo));
+
+ if (shmids(&idbuf, 0, &nids) < 0)
+ return (-errno);
+
+ shminfo.used_ids = nids;
+ if (uucopy(&shminfo, buf, sizeof (shminfo)) != 0)
+ return (-errno);
+
+ return (nids);
+}
+
+static int
+lx_shmctl_shmstat(int slot, void *buf)
+{
+ int r, shmid;
+
+ lx_debug("shmctl_shmstat(%d, 0x%p)\n", slot, buf);
+ shmid = slot_to_id(SLOT_SHM, slot);
+ if (shmid < 0)
+ return (shmid);
+
+ r = lx_shmctl_ipcstat(shmid, buf);
+ return (r < 0 ? r : shmid);
+}
+
+long
+lx_shmctl(int shmid, int cmd, void *buf)
+{
+ int r;
+ int use_errno = 0;
+
+ lx_debug("\tlx_shmctl(%d, %d, 0x%p)\n", shmid, cmd, buf);
+ switch (cmd & ~LX_IPC_64) {
+ case LX_IPC_RMID:
+ use_errno = 1;
+ r = shmctl(shmid, SHM_RMID, NULL); /* lx-private cmd */
+ break;
+
+ case LX_IPC_SET:
+ r = lx_shmctl_ipcset(shmid, buf);
+ break;
+
+ case LX_IPC_STAT:
+ r = lx_shmctl_ipcstat(shmid, buf);
+ break;
+
+ case LX_IPC_INFO:
+ r = lx_shmctl_ipcinfo(buf);
+ break;
+
+ case LX_SHM_LOCK:
+ use_errno = 1;
+ r = shmctl(shmid, SHM_LOCK, NULL);
+ break;
+
+ case LX_SHM_UNLOCK:
+ use_errno = 1;
+ r = shmctl(shmid, SHM_UNLOCK, NULL);
+ break;
+
+ case LX_SHM_INFO:
+ r = lx_shmctl_shminfo(buf);
+ break;
+
+ case LX_SHM_STAT:
+ r = lx_shmctl_shmstat(shmid, buf);
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+
+ if (use_errno == 1 && r < 0)
+ return (-errno);
+
+ return (r);
+}
+
+/*
+ * Under 32-bit Linux, glibc funnels all of the sysv IPC operations into this
+ * single ipc(2) system call. We need to blow that up and filter the
+ * remnants into the proper Solaris system calls.
+ */
+long
+lx_ipc(uintptr_t cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
+ uintptr_t arg4)
+{
+ int r;
+ void *bufptr = (void *)arg4;
+
+ lx_debug("lx_ipc(%d, %d, %d, %d, 0x%p, %d)\n",
+ cmd, arg1, arg2, arg3, bufptr, arg4);
+
+ switch (cmd) {
+ case LX_MSGGET:
+ r = lx_msgget((key_t)arg1, (int)arg2);
+ break;
+ case LX_MSGSND:
+ r = lx_msgsnd((int)arg1, bufptr, (size_t)arg2, (int)arg3);
+ break;
+ case LX_MSGRCV:
+ {
+ struct {
+ void *msgp;
+ long msgtype;
+ } args;
+
+ /*
+ * Rather than passing 5 args into ipc(2) directly,
+ * glibc passes 4 args and uses the buf argument to
+ * point to a structure containing two args: a pointer
+ * to the message and the message type.
+ */
+ if (uucopy(bufptr, &args, sizeof (args)))
+ return (-errno);
+ r = lx_msgrcv((int)arg1, args.msgp, (size_t)arg2,
+ args.msgtype, (int)arg3);
+ }
+ break;
+ case LX_MSGCTL:
+ r = lx_msgctl((int)arg1, (int)arg2, bufptr);
+ break;
+ case LX_SEMCTL:
+ r = lx_semctl((int)arg1, (size_t)arg2, (int)arg3, bufptr);
+ break;
+ case LX_SEMOP:
+ /*
+ * 'struct sembuf' is the same on Linux and Solaris, so we
+ * pass bufptr straight through.
+ */
+ r = lx_semop((int)arg1, bufptr, (size_t)arg2);
+ break;
+ case LX_SEMGET:
+ r = lx_semget((int)arg1, (size_t)arg2, (int)arg3);
+ break;
+ case LX_SHMAT:
+ r = lx_shmat((int)arg1, bufptr, (size_t)arg2);
+ if (r >= 0 || r <= -4096) {
+ if (uucopy(&r, (void *)arg3, sizeof (r)) != 0)
+ r = -errno;
+ }
+ break;
+ case LX_SHMDT:
+ r = shmdt(bufptr);
+ if (r < 0)
+ r = -errno;
+ break;
+ case LX_SHMGET:
+ r = lx_shmget((int)arg1, (size_t)arg2, (int)arg3);
+ break;
+ case LX_SHMCTL:
+ r = lx_shmctl((int)arg1, (int)arg2, bufptr);
+ break;
+
+ default:
+ r = -EINVAL;
+ }
+
+ return (r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/time.c b/usr/src/lib/brand/lx/lx_brand/common/time.c
new file mode 100644
index 0000000000..c810aa33f1
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/time.c
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/times.h>
+#include <sys/lx_syscall.h>
+#include <sys/lx_misc.h>
+
+/*
+ * times() - The Linux implementation avoids writing to NULL, while Illumos
+ * returns EFAULT.
+ */
+long
+lx_times(uintptr_t p1)
+{
+ clock_t ret;
+ struct tms buf, *tp = (struct tms *)p1;
+
+ ret = times(&buf);
+
+ if ((ret == -1) ||
+ ((tp != NULL) && uucopy((void *)&buf, tp, sizeof (buf)) != 0))
+ return (-errno);
+
+ return ((ret == -1) ? -errno : ret);
+}
+
+/*
+ * setitimer() - the Linux implementation can handle tv_usec values greater
+ * than 1,000,000 where Illumos would return EINVAL.
+ *
+ * There's still an issue here where Linux can handle a
+ * tv_sec value greater than 100,000,000 but Illumos cannot,
+ * but that would also mean setting an interval timer to fire
+ * over _three years_ in the future so it's unlikely anything
+ * other than Linux test suites will trip over it.
+ */
+long
+lx_setitimer(uintptr_t p1, uintptr_t p2, uintptr_t p3)
+{
+ struct itimerval itv;
+ struct itimerval *itp = (struct itimerval *)p2;
+
+ if (itp != NULL) {
+ if (uucopy(itp, &itv, sizeof (itv)) != 0)
+ return (-errno);
+
+ /*
+ * Adjust any tv_usec fields >= 1,000,000 by adding any whole
+ * seconds so indicated to tv_sec and leaving tv_usec as the
+ * remainder.
+ */
+ if (itv.it_interval.tv_usec >= MICROSEC) {
+ itv.it_interval.tv_sec +=
+ itv.it_interval.tv_usec / MICROSEC;
+
+ itv.it_interval.tv_usec %= MICROSEC;
+ }
+ if (itv.it_value.tv_usec >= MICROSEC) {
+ itv.it_value.tv_sec +=
+ itv.it_value.tv_usec / MICROSEC;
+
+ itv.it_value.tv_usec %= MICROSEC;
+ }
+
+ itp = &itv;
+ }
+
+ return ((setitimer((int)p1, itp, (struct itimerval *)p3) != 0) ?
+ -errno : 0);
+}
+
+/*
+ * NOTE: The Linux man pages state this structure is obsolete and is
+ * unsupported, so it is declared here for sizing purposes only.
+ */
+struct lx_timezone {
+ int tz_minuteswest; /* minutes W of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+long
+lx_settimeofday(uintptr_t p1, uintptr_t p2)
+{
+ struct timeval tv;
+ struct lx_timezone tz;
+
+ if ((p1 != NULL) &&
+ (uucopy((struct timeval *)p1, &tv, sizeof (tv)) < 0))
+ return (-errno);
+
+ /*
+ * The Linux man page states use of the second parameter is obsolete,
+ * but settimeofday(2) should still return EFAULT if it is set
+ * to a bad non-NULL pointer (sigh...)
+ */
+ if ((p2 != NULL) &&
+ (uucopy((struct lx_timezone *)p2, &tz, sizeof (tz)) < 0))
+ return (-errno);
+
+ if ((p1 != NULL) && (settimeofday(&tv, NULL) < 0))
+ return (-errno);
+
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/truncate.c b/usr/src/lib/brand/lx/lx_brand/common/truncate.c
new file mode 100644
index 0000000000..ba3e452408
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/common/truncate.c
@@ -0,0 +1,173 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/lx_types.h>
+#include <sys/lx_misc.h>
+#include <sys/lx_syscall.h>
+
+/*
+ * ZFS does not enforce the process.max-file-size rctl on a file which is
+ * grown in size via truncate/ftruncate, since that is simply metadata which
+ * does not consume any additional space. However, LTP truncate03 depends on
+ * this behavior so we enforce it here.
+ */
+static boolean_t
+p_fsize_excd(const char *path, off_t length)
+{
+ struct stat64 sb;
+ struct rlimit rl;
+
+ if (stat64(path, &sb) == 0 && sb.st_size < length) {
+ /* We are growing the file, check the rlimit */
+ if (getrlimit(RLIMIT_FSIZE, &rl) == 0 && length > rl.rlim_cur)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+static boolean_t
+f_fsize_excd(int fd, off_t length)
+{
+ struct stat64 sb;
+ struct rlimit rl;
+
+ if (fstat64(fd, &sb) == 0 && sb.st_size < length) {
+ /* We are growing the file, check the rlimit */
+ if (getrlimit(RLIMIT_FSIZE, &rl) == 0 && length > rl.rlim_cur)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * On Illumos, truncate() and ftruncate() are implemented in libc, so these are
+ * layered on those interfaces.
+ */
+
+long
+lx_truncate(uintptr_t path, uintptr_t length)
+{
+#if defined(_ILP32)
+ if ((off_t)length >= 0xffffffffUL)
+ return (-EFBIG);
+#endif
+
+ if (length > 0 && p_fsize_excd((const char *)path, (off_t)length))
+ return (-EFBIG);
+
+ return (truncate((const char *)path, (off_t)length) == 0 ? 0 : -errno);
+}
+
+long
+lx_ftruncate(uintptr_t fd, uintptr_t length)
+{
+ int r;
+
+#if defined(_ILP32)
+ if ((off_t)length >= 0xffffffffUL)
+ return (-EFBIG);
+#endif
+
+ if (length > 0 && f_fsize_excd((int)fd, (off_t)length))
+ return (-EFBIG);
+
+ r = ftruncate((int)fd, (off_t)length);
+ /*
+ * On Linux, truncating a file opened read-only returns EINVAL whereas
+ * Illumos returns EBADF.
+ */
+ if (r != 0) {
+ if (errno == EBADF) {
+ int mode;
+
+ if ((mode = fcntl(fd, F_GETFL, 0)) != -1 &&
+ (mode & O_ACCMODE) == O_RDONLY)
+ r = -EINVAL;
+ else
+ r = -EBADF; /* keep existing errno */
+ } else {
+ r = -errno;
+ }
+ }
+ return (r);
+}
+
+long
+lx_truncate64(uintptr_t path, uintptr_t length_lo, uintptr_t length_hi)
+{
+ uint64_t len = LX_32TO64(length_lo, length_hi);
+
+ if (len >= 0x7fffffffffffffffULL)
+ return (-EFBIG);
+
+ if (len > 0 && p_fsize_excd((const char *)path, (off_t)len))
+ return (-EFBIG);
+
+ return (truncate64((const char *)path, len) == 0 ? 0 : -errno);
+}
+
+long
+lx_ftruncate64(uintptr_t fd, uintptr_t length_lo, uintptr_t length_hi)
+{
+ int r;
+ uint64_t len = LX_32TO64(length_lo, length_hi);
+
+ if (len >= 0x7fffffffffffffffULL)
+ return (-EFBIG);
+
+ if (len > 0 && f_fsize_excd((int)fd, (off_t)len))
+ return (-EFBIG);
+
+ r = ftruncate64((int)fd, len);
+ /*
+ * On Linux, truncating a file opened read-only returns EINVAL whereas
+ * Illumos returns EBADF.
+ */
+ if (r != 0) {
+ if (errno == EBADF) {
+ int mode;
+
+ if ((mode = fcntl(fd, F_GETFL, 0)) != -1 &&
+ (mode & O_ACCMODE) == O_RDONLY)
+ r = -EINVAL;
+ else
+ r = -EBADF; /* keep existing errno */
+ } else {
+ r = -errno;
+ }
+ }
+
+ return (r);
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/Makefile b/usr/src/lib/brand/lx/lx_brand/i386/Makefile
new file mode 100644
index 0000000000..8723f64292
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/i386/Makefile
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
+#
+# lib/brand/lx/i386/Makefile
+
+ISASRCDIR=.
+
+ASFLAGS += -P -D_ASM
+
+include ../Makefile.com
+
+DYNFLAGS += -Wl,-I/native/lib/ld.so.1
+
+POFILE= lx_brand.po
+MSGFILES= $(CSRCS)
+
+ASSYMDEP_OBJS = lx_handler.o
+
+install: all $(ROOTLIBS)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/lx_crt.s b/usr/src/lib/brand/lx/lx_brand/i386/lx_crt.s
new file mode 100644
index 0000000000..c457c1c209
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/i386/lx_crt.s
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/asm_linkage.h>
+
+#if defined(lint)
+
+void
+_start(void)
+{
+}
+
+#else /* lint */
+
+ /*
+ * C language startup routine for the lx brand shared library.
+ */
+ ENTRY_NP(_start)
+ pushl $0 / Build a stack frame. retpc = NULL
+ pushl $0 / fp = NULL
+ movl %esp, %ebp / first stack frame
+
+ /*
+ * Calculate the location of the envp array by adding the size of
+ * the argv array to the start of the argv array.
+ */
+ movl 8(%ebp), %eax / argc in %eax
+ leal 16(%ebp,%eax,4), %edx / envp in %edx
+ andl $-16, %esp
+ pushl %edx / push envp
+ leal 12(%ebp),%edx / compute &argv[0]
+ pushl %edx / push argv
+ pushl %eax / push argc
+ call lx_init
+ /*
+ * lx_init will never return.
+ */
+ SET_SIZE(_start)
+
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s b/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s
new file mode 100644
index 0000000000..7afb9c4b7f
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/regset.h>
+#include <sys/segments.h>
+#include <sys/syscall.h>
+#include <sys/lx_brand.h>
+
+#if defined(_ASM)
+#include <sys/lx_signal.h>
+#include <sys/lx_syscall.h>
+#endif /* _ASM */
+
+/* 32-bit syscall numbers */
+#define LX_SYS_sigreturn 119
+#define LX_SYS_rt_sigreturn 173
+
+#if defined(lint)
+
+#include <sys/types.h>
+#include <sys/regset.h>
+#include <sys/signal.h>
+
+void
+lx_sigreturn_tramp(void)
+{}
+
+void
+lx_rt_sigreturn_tramp(void)
+{}
+
+#else /* lint */
+
+ ENTRY_NP(lx_swap_gs)
+ push %eax /* save the current eax value */
+ movl 0xc(%esp),%eax /* 2nd param is a pointer */
+ movw %gs,(%eax) /* use the pointer to save current gs */
+ movl 0x8(%esp),%eax /* first parameter is the new gs value */
+ movw %ax, %gs /* switch to the new gs value */
+ pop %eax /* restore eax */
+ ret
+ SET_SIZE(lx_swap_gs)
+
+ /*
+ * Trampoline code is called by the return at the end of a Linux
+ * signal handler to return control to the interrupted application
+ * via the lx_sigreturn() or lx_rt_sigreturn() syscalls.
+ *
+ * (lx_sigreturn() is called for legacy signal handling, and
+ * lx_rt_sigreturn() is called for "new"-style signals.)
+ *
+ * These two routines must consist of the EXACT code sequences below
+ * as gdb looks at the sequence of instructions a routine will return
+ * to determine whether it is in a signal handler or not.
+ * See the Linux code setup_signal_stack_sc() in arch/x86/um/signal.c.
+ */
+ ENTRY_NP(lx_sigreturn_tramp)
+ popl %eax
+ movl $LX_SYS_sigreturn, %eax
+ int $0x80
+ SET_SIZE(lx_sigreturn_tramp)
+
+ ENTRY_NP(lx_rt_sigreturn_tramp)
+ movl $LX_SYS_rt_sigreturn, %eax
+ int $0x80
+ SET_SIZE(lx_rt_sigreturn_tramp)
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_debug.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_debug.h
new file mode 100644
index 0000000000..18e452876a
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_debug.h
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#ifndef _LX_DEBUG_H
+#define _LX_DEBUG_H
+
+#include <lx_provider_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* initialize the debugging subsystem */
+extern void lx_debug_init(boolean_t, boolean_t, const char *);
+
+/* printf() style debug message functionality */
+extern void lx_debug(const char *, ...);
+
+extern int lx_debug_enabled;
+
+#define LX_DEBUG_ISENABLED \
+ (lx_debug_enabled || LX_DEBUG_ENABLED())
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LX_DEBUG_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
new file mode 100644
index 0000000000..5879311cef
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
@@ -0,0 +1,175 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_LX_H
+#define _SYS_LX_H
+
+#include <stdio.h>
+#include <alloca.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lwp.h>
+
+#include <sys/lx_brand.h>
+#include <sys/lx_thread.h>
+
+#include <lx_errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char lx_release[LX_KERN_RELEASE_MAX];
+extern char lx_cmd_name[MAXNAMLEN];
+extern pid_t zoneinit_pid;
+extern int lx_is_vforked;
+extern boolean_t lx_no_abort_handler;
+
+/*
+ * Values Linux expects for init
+ */
+#define LX_INIT_PID 1
+
+/*
+ * the maximum length of messages to be output with lx_msg(), lx_err(),
+ * lx_debug(), or lx_unsupported().
+ */
+#define LX_MSG_MAXLEN (128 + MAXPATHLEN)
+
+/*
+ * Linux scheduler priority ranges.
+ */
+#define LX_SCHED_PRIORITY_MIN_OTHER 0
+#define LX_SCHED_PRIORITY_MAX_OTHER 0
+#define LX_SCHED_PRIORITY_MIN_RRFIFO 1
+#define LX_SCHED_PRIORITY_MAX_RRFIFO 99
+
+/*
+ * Based on code from brand_misc.h, but use of that is incompatible with the
+ * lx brand.
+ *
+ * These macros invoke a brandsys subcommand, B_TRUSS_POINT, which makes it
+ * easy to debug with DTrace.
+ */
+#define B_TRUSS_POINT 6
+
+#define B_TRACE_POINT_5(a0, a1, a2, a3, a4) \
+ (void) syscall(SYS_brand, B_TRUSS_POINT, (a0), (a1), (a2), (a3), (a4))
+
+#define B_TRACE_POINT_4(a0, a1, a2, a3) \
+ B_TRACE_POINT_5((a0), (a1), (a2), (a3), 0)
+
+#define B_TRACE_POINT_3(a0, a1, a2) \
+ B_TRACE_POINT_5((a0), (a1), (a2), 0, 0)
+
+#define B_TRACE_POINT_2(a0, a1) \
+ B_TRACE_POINT_5((a0), (a1), 0, 0, 0)
+
+#define B_TRACE_POINT_1(a0) \
+ B_TRACE_POINT_5((a0), 0, 0, 0, 0)
+
+#define B_TRACE_POINT_0() \
+ B_TRACE_POINT_5(0, 0, 0, 0, 0)
+
+/*
+ * Macros to access register state within a ucontext_t:
+ */
+#define LX_REG(ucp, r) ((ucp)->uc_mcontext.gregs[(r)])
+
+/*
+ * normally we never want to write to stderr or stdout because it's unsafe
+ * to make assumptions about the underlying file descriptors. to protect
+ * against writes to these file descriptors we go ahead and close them
+ * our brand process initalization code. but there are still occasions
+ * where we are willing to make assumptions about our file descriptors
+ * and write to them. at thes times we should use one lx_msg() or
+ * lx_msg_error()
+ */
+extern void lx_msg(char *, ...);
+extern void lx_err(char *, ...);
+extern void lx_err_fatal(char *, ...);
+extern void lx_unsupported(char *, ...);
+
+struct ucontext;
+
+extern ucontext_t *lx_syscall_regs(void);
+extern uintptr_t lx_find_brand_sp(void);
+extern const ucontext_t *lx_find_brand_uc(void);
+
+extern void lx_jump_to_linux(ucontext_t *) __NORETURN;
+
+extern char *lx_fd_to_path(int fd, char *buf, int buf_size);
+extern int lx_lpid_to_spair(pid_t, pid_t *, lwpid_t *);
+extern int lx_lpid_to_spid(pid_t, pid_t *);
+
+extern void lx_ptrace_init();
+extern int lx_ptrace_wait(siginfo_t *);
+extern void lx_ptrace_fork(void);
+extern void lx_ptrace_stop_if_option(int, boolean_t, ulong_t msg, ucontext_t *);
+extern void lx_ptrace_clone_begin(int, boolean_t, int);
+
+extern int lx_check_alloca(size_t);
+#define SAFE_ALLOCA(sz) (lx_check_alloca(sz) ? alloca(sz) : NULL)
+
+extern void lx_init_tsd(lx_tsd_t *);
+extern int lx_alloc_stack(void **, size_t *);
+extern void lx_install_stack(void *, size_t, lx_tsd_t *);
+extern void lx_free_stack(void);
+extern void lx_free_other_stacks(void);
+extern void lx_stack_prefork(void);
+extern void lx_stack_postfork(void);
+
+/*
+ * NO_UUCOPY disables calls to the uucopy* system calls to help with
+ * debugging brand library accesses to linux application memory.
+ */
+#ifdef NO_UUCOPY
+
+int uucopy_unsafe(const void *src, void *dst, size_t n);
+int uucopystr_unsafe(const void *src, void *dst, size_t n);
+
+#define uucopy(src, dst, n) uucopy_unsafe((src), (dst), (n))
+#define uucopystr(src, dst, n) uucopystr_unsafe((src), (dst), (n))
+
+#endif /* NO_UUCOPY */
+
+/*
+ * We use these Private libc interfaces to defer signals during critical
+ * sections.
+ */
+extern void _sigon(void);
+extern void _sigoff(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_mount.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_mount.h
new file mode 100644
index 0000000000..f9b239150d
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_mount.h
@@ -0,0 +1,163 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#ifndef _LX_MOUNT_H
+#define _LX_MOUNT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rpc/rpc.h>
+#include <nfs/nfs.h>
+
+extern int lx_nfs_mount(char *, char *, char *, int, char *);
+
+/*
+ * mount() is significantly different between Linux and Solaris. The main
+ * difference is between the set of flags. Some flags on Linux can be
+ * translated to a Solaris equivalent, some are converted to a
+ * filesystem-specific option, while others have no equivalent whatsoever.
+ */
+#define LX_MS_MGC_VAL 0xC0ED0000
+#define LX_MS_RDONLY 0x00000001
+#define LX_MS_NOSUID 0x00000002
+#define LX_MS_NODEV 0x00000004
+#define LX_MS_NOEXEC 0x00000008
+#define LX_MS_SYNCHRONOUS 0x00000010
+#define LX_MS_REMOUNT 0x00000020
+#define LX_MS_MANDLOCK 0x00000040
+#define LX_MS_NOATIME 0x00000400
+#define LX_MS_NODIRATIME 0x00000800
+#define LX_MS_BIND 0x00001000
+#define LX_MS_MOVE 0x00002000
+#define LX_MS_REC 0x00004000
+#define LX_MS_SILENT 0x00008000
+#define LX_MS_POSIXACL 0x00010000
+#define LX_MS_UNBINDABLE 0x00020000
+#define LX_MS_PRIVATE 0x00040000
+#define LX_MS_SLAVE 0x00080000
+#define LX_MS_SHARED 0x00100000
+#define LX_MS_RELATIME 0x00200000
+#define LX_MS_KERNMOUNT 0x00400000
+#define LX_MS_I_VERSION 0x00800000
+#define LX_MS_STRICTATIME 0x01000000
+#define LX_MS_LAZYTIME 0x02000000
+
+/* internal flags - ignored if passed in */
+#define LX_MS_NOSEC 0x10000000
+#define LX_MS_BORN 0x20000000
+#define LX_MS_ACTIVE 0x40000000
+#define LX_MS_NOUSER 0x80000000
+
+#define LX_MS_SUPPORTED (LX_MS_MGC_VAL | \
+ LX_MS_RDONLY | LX_MS_NOSUID | \
+ LX_MS_NODEV | LX_MS_NOEXEC | \
+ LX_MS_REMOUNT | LX_MS_NOATIME | \
+ LX_MS_NODIRATIME | LX_MS_BIND | LX_MS_SILENT | \
+ LX_MS_STRICTATIME | LX_MS_NOSEC | \
+ LX_MS_BORN | LX_MS_ACTIVE | LX_MS_NOUSER)
+
+/*
+ * support for nfs mounts
+ */
+#define LX_NMD_MAXHOSTNAMELEN 256
+
+#define LX_NFS_MOUNT_SOFT 0x00000001
+#define LX_NFS_MOUNT_INTR 0x00000002
+#define LX_NFS_MOUNT_SECURE 0x00000004
+#define LX_NFS_MOUNT_POSIX 0x00000008
+#define LX_NFS_MOUNT_NOCTO 0x00000010
+#define LX_NFS_MOUNT_NOAC 0x00000020
+#define LX_NFS_MOUNT_TCP 0x00000040
+#define LX_NFS_MOUNT_VER3 0x00000080
+#define LX_NFS_MOUNT_KERBEROS 0x00000100
+#define LX_NFS_MOUNT_NONLM 0x00000200
+#define LX_NFS_MOUNT_BROKEN_SUID 0x00000400
+#define LX_NFS_MOUNT_SUPPORTED (LX_NFS_MOUNT_SOFT | \
+ LX_NFS_MOUNT_INTR | \
+ LX_NFS_MOUNT_POSIX | \
+ LX_NFS_MOUNT_NOCTO | \
+ LX_NFS_MOUNT_NOAC | \
+ LX_NFS_MOUNT_TCP | \
+ LX_NFS_MOUNT_VER3 | \
+ LX_NFS_MOUNT_NONLM)
+
+#define LX_NMD_DEFAULT_RSIZE 0
+#define LX_NMD_DEFAULT_WSIZE 0
+
+/*
+ * the nfs v3 file handle structure definitions are _almost_ the same
+ * on linux and solaris. the key difference are:
+ *
+ * 1) on linux fh3_length is an unsigned short where as on solaris it's
+ * an int.
+ *
+ * 2) on linux the file handle data doesn't 32 bit members, so the structure
+ * is not 32 bit aligned. (where as on solaris it is.)
+ *
+ * so rather than defining a structure that would allow us to intrepret
+ * all the contents of the nfs v3 file handle here, we decide to treate
+ * the file handle as an array of chars. this works just fine since it
+ * avoids the alignment issues and the actual file handle handle contects
+ * are defined by the nfs specification so they are common across solaris
+ * and linux. we do the same thing for nfs v2 file handles.
+ */
+struct lx_nfs_fh2 {
+ unsigned char lx_fh_data[NFS_FHSIZE];
+} lx_nfs_fh2;
+
+struct lx_nfs_fh3 {
+ unsigned short lx_fh3_length;
+ unsigned char lx_fh3_data[NFS3_FHSIZE];
+} lx_nfs_fh3;
+
+typedef struct lx_nfs_mount_data {
+ int nmd_version;
+ int nmd_fd;
+ struct lx_nfs_fh2 nmd_old_root;
+ int nmd_flags;
+ int nmd_rsize;
+ int nmd_wsize;
+ int nmd_timeo;
+ int nmd_retrans;
+ int nmd_acregmin;
+ int nmd_acregmax;
+ int nmd_acdirmin;
+ int nmd_acdirmax;
+ struct sockaddr_in nmd_addr;
+ char nmd_hostname[LX_NMD_MAXHOSTNAMELEN];
+ int nmd_namlen;
+ uint_t nmd_bsize;
+ struct lx_nfs_fh3 nmd_root;
+} lx_nfs_mount_data_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LX_MOUNT_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
new file mode 100644
index 0000000000..99abdbbf46
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_poll.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_LX_POLL_H
+#define _SYS_LX_POLL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * These events are identical between Linux and Solaris
+ */
+#define LX_POLLIN 0x001
+#define LX_POLLPRI 0x002
+#define LX_POLLOUT 0x004
+#define LX_POLLERR 0x008
+#define LX_POLLHUP 0x010
+#define LX_POLLNVAL 0x020
+#define LX_POLLRDNORM 0x040
+#define LX_POLLRDBAND 0x080
+
+#define LX_POLL_COMMON_EVENTS (LX_POLLIN | LX_POLLPRI | LX_POLLOUT | \
+ LX_POLLERR | LX_POLLHUP | LX_POLLNVAL | LX_POLLRDNORM | LX_POLLRDBAND)
+
+/*
+ * These events differ between Linux and Solaris
+ */
+#define LX_POLLWRNORM 0x0100
+#define LX_POLLWRBAND 0x0200
+#define LX_POLLRDHUP 0x2000
+
+
+#define LX_POLL_SUPPORTED_EVENTS \
+ (LX_POLL_COMMON_EVENTS | LX_POLLWRNORM | LX_POLLWRBAND | LX_POLLRDHUP)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_POLL_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
new file mode 100644
index 0000000000..9d77524410
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _SYS_LX_SIGNAL_H
+#define _SYS_LX_SIGNAL_H
+
+#if !defined(_ASM)
+#include <sys/lx_types.h>
+#include <sys/ucontext.h>
+#include <sys/lx_siginfo.h>
+#include <lx_signum.h>
+
+#endif /* !defined(_ASM) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Linux sigaction flags
+ */
+#define LX_SA_NOCLDSTOP 0x00000001
+#define LX_SA_NOCLDWAIT 0x00000002
+#define LX_SA_SIGINFO 0x00000004
+#define LX_SA_RESTORER 0x04000000
+#define LX_SA_ONSTACK 0x08000000
+#define LX_SA_RESTART 0x10000000
+#define LX_SA_NODEFER 0x40000000
+#define LX_SA_RESETHAND 0x80000000
+#define LX_SA_NOMASK LX_SA_NODEFER
+#define LX_SA_ONESHOT LX_SA_RESETHAND
+
+#define LX_SIG_BLOCK 0
+#define LX_SIG_UNBLOCK 1
+#define LX_SIG_SETMASK 2
+
+#define LX_MINSIGSTKSZ 2048
+#define LX_SS_ONSTACK 1
+#define LX_SS_DISABLE 2
+
+#define LX_SIGRT_MAGIC 0xdeadf00d
+
+#if !defined(_ASM)
+
+typedef struct lx_sigaction {
+ void (*lxsa_handler)();
+ int lxsa_flags;
+ void (*lxsa_restorer)(void);
+ lx_sigset_t lxsa_mask;
+} lx_sigaction_t;
+
+#if defined(_ILP32)
+typedef uint32_t lx_osigset_t;
+
+#define OSIGSET_NBITS (sizeof (lx_osigset_t) * NBBY)
+#define OSIGSET_BITSET(sig) (1U << (((sig) - 1) % OSIGSET_NBITS))
+
+typedef struct lx_osigaction {
+ void (*lxsa_handler)();
+ lx_osigset_t lxsa_mask;
+ int lxsa_flags;
+ void (*lxsa_restorer)(void);
+} lx_osigaction_t;
+#endif
+
+/*
+ * Flag settings to determine whether common routines should operate on
+ * lx_sigset_ts or lx_osigset_ts.
+ */
+#define USE_OSIGSET 0
+#define USE_SIGSET 1
+
+typedef struct lx_sighandlers {
+ struct lx_sigaction lx_sa[LX_NSIG + 1];
+} lx_sighandlers_t;
+
+typedef struct lx_sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} lx_stack_t;
+
+/*
+ * _fpreg, _fpxreg, _xmmreg and _fpstate are defined in Linux src in:
+ * arch/x86/include/uapi/asm/sigcontext.h
+ */
+#define LX_X86_FXSR_MAGIC 0x0000
+#define LX_X86_FXSR_NONE 0xffff
+
+#if defined(_LP64)
+
+typedef struct lx_fpstate {
+ ushort_t cwd;
+ ushort_t swd;
+ ushort_t twd; /* Note this is not the same as the 32bit/x87/FSAVE twd */
+ ushort_t fop;
+ uint64_t rip;
+ uint64_t rdp;
+ uint32_t mxcsr;
+ uint32_t mxcsr_mask;
+ uint32_t st_space[32]; /* 8 * 16 bytes for each FP-reg */
+ uint32_t xmm_space[64]; /* 16 * 16 bytes for each XMM-reg */
+ uint32_t reserved2[12];
+ uint32_t reserved3[12];
+} lx_fpstate_t;
+
+/*
+ * The Linux layout is defined in the Linux src tree in:
+ * arch/x86/include/asm/sigcontext.h
+ * and the user-level def (which is what we want) at:
+ * arch/x86/include/uapi/asm/sigcontext.h
+ *
+ * The Illumos offsets of the registers in the context are defined in:
+ * usr/src/uts/intel/sys/regset.h
+ * this is an mcontext_t from uc_mcontext.
+ *
+ * For the 64-bit case the register layout is completely different in the
+ * context.
+ */
+typedef struct lx_sigcontext {
+ ulong_t sc_r8;
+ ulong_t sc_r9;
+ ulong_t sc_r10;
+ ulong_t sc_r11;
+ ulong_t sc_r12;
+ ulong_t sc_r13;
+ ulong_t sc_r14;
+ ulong_t sc_r15;
+ ulong_t sc_rdi;
+ ulong_t sc_rsi;
+ ulong_t sc_rbp;
+ ulong_t sc_rbx;
+ ulong_t sc_rdx;
+ ulong_t sc_rax;
+ ulong_t sc_rcx;
+ ulong_t sc_rsp;
+ ulong_t sc_rip;
+ ulong_t sc_eflags;
+ ushort_t sc_cs;
+ ushort_t sc_gs;
+ ushort_t sc_fs;
+ ushort_t sc_pad0;
+ ulong_t sc_err;
+ ulong_t sc_trapno;
+
+ ulong_t sc_mask;
+ ulong_t sc_cr2;
+ lx_fpstate_t *sc_fpstate;
+
+ ulong_t reserved[8];
+} lx_sigcontext_t;
+
+#else /* is _ILP32 */
+
+struct lx_fpreg {
+ ushort_t significand[4];
+ ushort_t exponent;
+};
+
+struct lx_fpxreg {
+ ushort_t significand[4];
+ ushort_t exponent;
+ ushort_t padding[3];
+};
+
+struct lx_xmmreg {
+ uint32_t element[4];
+};
+
+typedef struct lx_fpstate {
+ /* Regular FPU environment */
+ ulong_t cw;
+ ulong_t sw;
+ ulong_t tag;
+ ulong_t ipoff;
+ ulong_t cssel;
+ ulong_t dataoff;
+ ulong_t datasel;
+ struct lx_fpreg _st[8];
+ ushort_t status;
+ ushort_t magic; /* 0xffff = regular FPU data */
+
+ /* FXSR FPU environment */
+ ulong_t _fxsr_env[6]; /* env is ignored */
+ ulong_t mxcsr;
+ ulong_t reserved;
+ struct lx_fpxreg _fxsr_st[8]; /* reg data is ignored */
+ struct lx_xmmreg _xmm[8];
+ ulong_t padding[56];
+} lx_fpstate_t;
+
+/*
+ * The Linux layout is defined in the Linux src tree in:
+ * arch/x86/include/asm/sigcontext.h
+ * and the user-level def (which is what we want) at:
+ * arch/x86/include/uapi/asm/sigcontext.h
+ *
+ * The Illumos offsets of the registers in the context are defined by the
+ * i386 ABI (see usr/src/uts/intel/sys/regset.h).
+ *
+ * Both Illumos and Linux match up here.
+ */
+typedef struct lx_sigcontext {
+ ulong_t sc_gs;
+ ulong_t sc_fs;
+ ulong_t sc_es;
+ ulong_t sc_ds;
+ ulong_t sc_edi;
+ ulong_t sc_esi;
+ ulong_t sc_ebp;
+ ulong_t sc_esp;
+ ulong_t sc_ebx;
+ ulong_t sc_edx;
+ ulong_t sc_ecx;
+ ulong_t sc_eax;
+ ulong_t sc_trapno;
+ ulong_t sc_err;
+ ulong_t sc_eip;
+ ulong_t sc_cs;
+ ulong_t sc_eflags;
+ ulong_t sc_esp_at_signal;
+ ulong_t sc_ss;
+
+ lx_fpstate_t *sc_fpstate;
+ ulong_t sc_mask;
+ ulong_t sc_cr2;
+} lx_sigcontext_t;
+#endif
+
+typedef struct lx_ucontext {
+ ulong_t uc_flags; /* Linux always sets this to 0 */
+ struct lx_ucontext *uc_link; /* Linux always sets this to NULL */
+ lx_stack_t uc_stack;
+ lx_sigcontext_t uc_sigcontext;
+ lx_sigset_t uc_sigmask;
+} lx_ucontext_t;
+
+typedef struct lx_sigbackup lx_sigbackup_t;
+struct lx_sigbackup {
+ ucontext_t *lxsb_retucp;
+ ucontext_t *lxsb_sigucp;
+ uintptr_t lxsb_sigdeliver_frame;
+ lx_sigbackup_t *lxsb_previous;
+};
+
+extern const int ltos_signo[];
+extern const int stol_signo[];
+
+extern void setsigacthandler(void (*)(int, siginfo_t *, void *),
+ void (**)(int, siginfo_t *, void *),
+ int (*)(const ucontext_t *));
+
+extern int lx_siginit(void);
+extern void lx_sighandlers_save(lx_sighandlers_t *);
+extern void lx_sighandlers_restore(lx_sighandlers_t *);
+
+extern int stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop);
+extern int stol_status(int);
+
+#endif /* !defined(_ASM) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_SIGNAL_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_sigstack.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_sigstack.h
new file mode 100644
index 0000000000..fbbf462389
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_sigstack.h
@@ -0,0 +1,78 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _SYS_LX_SIGSTACK_H
+#define _SYS_LX_SIGSTACK_H
+
+#if !defined(_ASM)
+#include <sys/lx_types.h>
+#include <sys/ucontext.h>
+#include <sys/lx_signal.h>
+#include <lx_signum.h>
+
+#endif /* !defined(_ASM) */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Two flavors of Linux signal stacks:
+ *
+ * lx_sigstack - used for "modern" signal handlers, in practice those
+ * that have the sigaction(2) flag SA_SIGINFO set
+ *
+ * lx_oldsigstack - used for legacy signal handlers, those that do not have
+ * the sigaction(2) flag SA_SIGINFO set or that were setup via
+ * the signal(2) call.
+ *
+ * NOTE: Since these structures will be placed on the stack and stack math will
+ * be done with their sizes, for the 32-bit code they must be word
+ * aligned in size (4 bytes) so the stack remains word aligned per the
+ * i386 ABI, or, for 64-bit code they must be 16 byte aligned as per the
+ * AMD64 ABI.
+ *
+ * The precise layout of these stack frames is also potentially
+ * depended on by particularly esoteric (or broken) software, and
+ * should be preserved. The Linux structures (rt_sigframe, et al)
+ * are defined in "arch/x86/include/asm/sigframe.h".
+ */
+#if defined(_LP64)
+typedef struct lx_sigstack {
+ void (*retaddr)(); /* address of real lx_rt_sigreturn code */
+ lx_ucontext_t uc; /* saved user context */
+ lx_siginfo_t si; /* saved signal information */
+ lx_fpstate_t fpstate; /* saved FP state */
+ char pad[2]; /* stack alignment */
+} lx_sigstack_t;
+#else
+struct lx_sigstack {
+ void (*retaddr)(); /* address of real lx_rt_sigreturn code */
+ int sig; /* signal number */
+ lx_siginfo_t *sip; /* points to "si" if valid, NULL if not */
+ lx_ucontext_t *ucp; /* points to "uc" */
+ lx_siginfo_t si; /* saved signal information */
+ lx_ucontext_t uc; /* saved user context */
+ lx_fpstate_t fpstate; /* saved FP state */
+ char trampoline[8]; /* code for trampoline to lx_rt_sigreturn() */
+};
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_SIGSTACK_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h
new file mode 100644
index 0000000000..2bbc31a234
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_socket.h
@@ -0,0 +1,147 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _SYS_LX_SOCKET_H
+#define _SYS_LX_SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/lx_types.h>
+
+/*
+ * Linux address family definitions
+ * Some of these are not supported
+ */
+#define LX_AF_UNSPEC 0 /* Unspecified */
+#define LX_AF_UNIX 1 /* local file/pipe name */
+#define LX_AF_INET 2 /* IP protocol family */
+#define LX_AF_AX25 3 /* Amateur Radio AX.25 */
+#define LX_AF_IPX 4 /* Novell Internet Protocol */
+#define LX_AF_APPLETALK 5 /* Appletalk */
+#define LX_AF_NETROM 6 /* Amateur radio */
+#define LX_AF_BRIDGE 7 /* Multiprotocol bridge */
+#define LX_AF_ATMPVC 8 /* ATM PVCs */
+#define LX_AF_X25 9 /* X.25 */
+#define LX_AF_INET6 10 /* IPV 6 */
+#define LX_AF_ROSE 11 /* Amateur Radio X.25 */
+#define LX_AF_DECnet 12 /* DECnet */
+#define LX_AF_NETBEUI 13 /* 802.2LLC */
+#define LX_AF_SECURITY 14 /* Security callback */
+#define LX_AF_KEY 15 /* key management */
+#define LX_AF_ROUTE 16 /* Alias to emulate 4.4BSD */
+#define LX_AF_PACKET 17 /* Packet family */
+#define LX_AF_ASH 18 /* Ash ? */
+#define LX_AF_ECONET 19 /* Acorn Econet */
+#define LX_AF_ATMSVC 20 /* ATM SVCs */
+#define LX_AF_SNA 22 /* Linux SNA */
+#define LX_AF_IRDA 23 /* IRDA sockets */
+#define LX_AF_PPPOX 24 /* PPPoX sockets */
+#define LX_AF_WANPIPE 25 /* Wanpipe API sockets */
+#define LX_AF_BLUETOOTH 31 /* Bluetooth sockets */
+#define LX_AF_MAX 33 /* MAX socket type */
+
+#define AF_NOTSUPPORTED -1
+#define AF_INVAL -2
+
+/*
+ * Linux ARP protocol hardware identifiers
+ */
+#define LX_ARPHRD_ETHER 1 /* Ethernet */
+#define LX_ARPHRD_LOOPBACK 772 /* Loopback */
+#define LX_ARPHRD_VOID 0xffff /* Unknown */
+
+/*
+ * Linux socket type definitions
+ */
+#define LX_SOCK_STREAM 1 /* Connection-based byte streams */
+#define LX_SOCK_DGRAM 2 /* Connectionless, datagram */
+#define LX_SOCK_RAW 3 /* Raw protocol interface */
+#define LX_SOCK_RDM 4 /* Reliably-delivered message */
+#define LX_SOCK_SEQPACKET 5 /* Sequenced packet stream */
+#define LX_SOCK_PACKET 10 /* Linux specific */
+#define LX_SOCK_MAX 11
+
+/*
+ * The Linux socket type can be or-ed with other flags (e.g. SOCK_CLOEXEC).
+ */
+#define LX_SOCK_TYPE_MASK 0xf
+
+/*
+ * Linux flags for socket, socketpair and accept4. These are or-ed into the
+ * socket type value. In the Linux net.h header these come from fcntl.h (note
+ * that they are in octal in the Linux header).
+ */
+#define LX_SOCK_CLOEXEC 0x80000
+#define LX_SOCK_NONBLOCK 0x800
+
+#define SOCK_NOTSUPPORTED -1
+#define SOCK_INVAL -2
+
+/*
+ * PF_PACKET protocol definitions.
+ */
+#define LX_ETH_P_802_3 0x0001
+#define LX_ETH_P_ALL 0x0003
+#define LX_ETH_P_802_2 0x0004
+#define LX_ETH_P_IP 0x0800
+#define LX_ETH_P_ARP 0x0806
+#define LX_ETH_P_IPV6 0x86DD
+
+/*
+ * Linux socketcall indices.
+ * These constitute all 17 socket related system calls
+ *
+ * These system calls are called via a single system call socketcall().
+ * The first arg being the endex of the system call type
+ */
+#define LX_SOCKET 1
+#define LX_BIND 2
+#define LX_CONNECT 3
+#define LX_LISTEN 4
+#define LX_ACCEPT 5
+#define LX_GETSOCKNAME 6
+#define LX_GETPEERNAME 7
+#define LX_SOCKETPAIR 8
+#define LX_SEND 9
+#define LX_RECV 10
+#define LX_SENDTO 11
+#define LX_RECVFROM 12
+#define LX_SHUTDOWN 13
+#define LX_SETSOCKOPT 14
+#define LX_GETSOCKOPT 15
+#define LX_SENDMSG 16
+#define LX_RECVMSG 17
+#define LX_ACCEPT4 18
+#define LX_RECVMMSG 19
+#define LX_SENDMMSG 20
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_SOCKET_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_statfs.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_statfs.h
new file mode 100644
index 0000000000..02f1a9b32b
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_statfs.h
@@ -0,0 +1,85 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LX_STATFS_H
+#define _LX_STATFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int lx_statfs_init(void);
+
+struct lx_statfs {
+ size_t f_type;
+ size_t f_bsize;
+ ulong_t f_blocks;
+ ulong_t f_bfree;
+ ulong_t f_bavail;
+ ulong_t f_files;
+ ulong_t f_ffree;
+ u_longlong_t f_fsid;
+ size_t f_namelen;
+ size_t f_frsize;
+ size_t f_spare[5];
+};
+
+struct lx_statfs64 {
+ int f_type;
+ int f_bsize;
+ u_longlong_t f_blocks;
+ u_longlong_t f_bfree;
+ u_longlong_t f_bavail;
+ u_longlong_t f_files;
+ u_longlong_t f_ffree;
+ u_longlong_t f_fsid;
+ int f_namelen;
+ int f_frsize;
+ int f_spare[5];
+};
+
+/*
+ * These magic values are taken mostly from statfs(2) or magic.h
+ */
+#define LX_AUTOFS_SUPER_MAGIC 0x0187
+#define LX_CGROUP_SUPER_MAGIC 0x27e0eb
+#define LX_DEVFS_SUPER_MAGIC 0x1373
+#define LX_DEVPTS_SUPER_MAGIC 0x1cd1
+#define LX_EXT2_SUPER_MAGIC 0xEF53
+#define LX_ISOFS_SUPER_MAGIC 0x9660
+#define LX_MSDOS_SUPER_MAGIC 0x4d44
+#define LX_NFS_SUPER_MAGIC 0x6969
+#define LX_PROC_SUPER_MAGIC 0x9fa0
+#define LX_SYSFS_SUPER_MAGIC 0x62656572
+#define LX_TMPFS_SUPER_MAGIC 0x01021994
+#define LX_UFS_MAGIC 0x00011954
+#define LX_PIPEFS_MAGIC 0x50495045
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LX_STATFS_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
new file mode 100644
index 0000000000..2c8db5cd32
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#ifndef _SYS_LX_SYSCALL_H
+#define _SYS_LX_SYSCALL_H
+
+#include <sys/lx_brand.h>
+
+#if !defined(_ASM)
+
+#include <sys/types.h>
+#include <sys/procset.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int lx_install;
+
+extern long lx_mknodat(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_futimesat(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_utimensat(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_fstatat64(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_stat(uintptr_t, uintptr_t);
+extern long lx_fstat(uintptr_t, uintptr_t);
+extern long lx_lstat(uintptr_t, uintptr_t);
+extern long lx_stat64(uintptr_t, uintptr_t);
+extern long lx_fstat64(uintptr_t, uintptr_t);
+extern long lx_lstat64(uintptr_t, uintptr_t);
+extern long lx_fcntl(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_fcntl64(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_flock(uintptr_t, uintptr_t);
+extern long lx_readdir(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_execve(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_ioctl(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_settimeofday(uintptr_t, uintptr_t);
+extern long lx_mknod(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_capget(uintptr_t, uintptr_t);
+extern long lx_capset(uintptr_t, uintptr_t);
+
+extern long lx_clock_nanosleep(int, int flags, struct timespec *,
+ struct timespec *);
+extern long lx_adjtimex(void *);
+extern long lx_timer_settime(timer_t, int, struct itimerspec *,
+ struct itimerspec *);
+extern long lx_timer_gettime(timer_t, struct itimerspec *);
+extern long lx_timer_getoverrun(timer_t);
+extern long lx_timer_delete(timer_t);
+
+extern long lx_truncate(uintptr_t, uintptr_t);
+extern long lx_ftruncate(uintptr_t, uintptr_t);
+extern long lx_truncate64(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_ftruncate64(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_sysctl(uintptr_t);
+extern long lx_fsync(uintptr_t);
+extern long lx_fdatasync(uintptr_t);
+extern long lx_rmdir(uintptr_t);
+extern long lx_utime(uintptr_t, uintptr_t);
+extern long lx_sysfs(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_uname(uintptr_t);
+extern long lx_getgroups16(uintptr_t, uintptr_t);
+extern long lx_setgroups(uintptr_t, uintptr_t);
+extern long lx_setgroups16(uintptr_t, uintptr_t);
+
+extern long lx_query_module(uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+
+extern long lx_times(uintptr_t);
+extern long lx_setitimer(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_clone(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_exit(uintptr_t);
+extern long lx_group_exit(uintptr_t);
+
+extern long lx_mmap(uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t);
+extern long lx_mmap2(uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t);
+extern long lx_remap(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_mount(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_statfs(uintptr_t, uintptr_t);
+extern long lx_fstatfs(uintptr_t, uintptr_t);
+extern long lx_statfs64(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_fstatfs64(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_sigreturn(void);
+extern long lx_rt_sigreturn(void);
+extern long lx_signal(uintptr_t, uintptr_t);
+extern long lx_sigaction(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_rt_sigaction(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_sigaltstack(uintptr_t, uintptr_t);
+extern long lx_sigpending(uintptr_t);
+extern long lx_rt_sigpending(uintptr_t, uintptr_t);
+extern long lx_sigprocmask(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_rt_sigprocmask(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_sigsuspend(uintptr_t);
+extern long lx_rt_sigsuspend(uintptr_t, uintptr_t);
+extern long lx_rt_sigwaitinfo(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_rt_sigtimedwait(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_rt_sigqueueinfo(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_rt_tgsigqueueinfo(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_futex(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+
+extern long lx_tkill(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+extern long lx_tgkill(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+
+extern long lx_sendfile(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_sendfile64(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_fork(void);
+extern long lx_vfork(void);
+extern long lx_exec(uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_ptrace(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_xattr2(uintptr_t, uintptr_t);
+extern long lx_xattr3(uintptr_t, uintptr_t, uintptr_t);
+extern long lx_xattr4(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+
+extern long lx_keyctl(void);
+
+extern long lx_ipc(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
+extern long lx_msgget(key_t, int);
+extern long lx_msgsnd(int, void *, size_t, int);
+extern long lx_msgrcv(int, void *, size_t, long, int);
+extern long lx_msgctl(int, int, void *);
+extern long lx_semget(key_t, int, int);
+extern long lx_semop(int, void *, size_t);
+extern long lx_semtimedop(int, void *, size_t, struct timespec *);
+extern long lx_semctl(int, int, int, void *);
+extern long lx_shmget(key_t, size_t, int);
+extern long lx_shmat(int, void *, int);
+extern long lx_shmctl(int, int, void *);
+
+extern long lx_getgroups(int, gid_t *);
+extern long lx_inotify_add_watch(int, const char *, uint32_t);
+extern long lx_inotify_init(void);
+extern long lx_inotify_init1(int);
+extern long lx_inotify_rm_watch(int, int);
+extern long lx_shmdt(char *);
+extern long lx_signalfd(int, uintptr_t, size_t);
+extern long lx_signalfd4(int, uintptr_t, size_t, int);
+extern long lx_timerfd_create(int, int);
+extern long lx_timerfd_settime(int, int,
+ const struct itimerspec *, struct itimerspec *);
+extern long lx_timerfd_gettime(int, struct itimerspec *);
+extern long lx_utimes(const char *, const struct timeval *);
+
+#endif /* !defined(_ASM) */
+
+
+#if defined(_LP64)
+#define LX_SYS_clone 56
+#define LX_SYS_vfork 58
+#else
+#define LX_SYS_clone 120
+#define LX_SYS_vfork 190
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_SYSCALL_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_sysv_ipc.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_sysv_ipc.h
new file mode 100644
index 0000000000..f9f49598b7
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_sysv_ipc.h
@@ -0,0 +1,222 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LX_SYSV_IPC_H
+#define _LX_SYSV_IPC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * msg-related definitions.
+ */
+#define LX_IPC_CREAT 00001000
+#define LX_IPC_EXCL 00002000
+#define LX_IPC_NOWAIT 00004000
+
+#define LX_IPC_RMID 0
+#define LX_IPC_SET 1
+#define LX_IPC_STAT 2
+#define LX_IPC_INFO 3
+
+#define LX_IPC_64 0x0100
+
+#define LX_SEMOP 1
+#define LX_SEMGET 2
+#define LX_SEMCTL 3
+#define LX_MSGSND 11
+#define LX_MSGRCV 12
+#define LX_MSGGET 13
+#define LX_MSGCTL 14
+#define LX_SHMAT 21
+#define LX_SHMDT 22
+#define LX_SHMGET 23
+#define LX_SHMCTL 24
+
+#define LX_MSG_STAT 11
+#define LX_MSG_INFO 12
+
+#define LX_MSG_NOERROR 010000
+
+/*
+ * Linux hard codes the maximum msgbuf length to be 8192 bytes. Really.
+ */
+#define LX_MSGMAX 8192
+
+struct lx_ipc_perm {
+ key_t key;
+ uid_t uid;
+ uid_t gid;
+ uid_t cuid;
+ uid_t cgid;
+ ushort_t mode;
+ ushort_t _pad1;
+ ushort_t seq;
+ ushort_t _pad2;
+ ulong_t _unused1;
+ ulong_t _unused2;
+};
+
+struct lx_msqid_ds {
+ struct lx_ipc_perm msg_perm;
+ time_t msg_stime;
+#if defined(_ILP32)
+ ulong_t _unused1;
+#endif
+ time_t msg_rtime;
+#if defined(_ILP32)
+ ulong_t _unused2;
+#endif
+ time_t msg_ctime;
+#if defined(_ILP32)
+ ulong_t _unused3;
+#endif
+ ulong_t msg_cbytes;
+ ulong_t msg_qnum;
+ ulong_t msg_qbytes;
+ pid_t msg_lspid;
+ pid_t msg_lrpid;
+ ulong_t _unused4;
+ ulong_t _unused5;
+};
+
+struct lx_msginfo {
+ int msgpool;
+ int msgmap;
+ int msgmax;
+ int msgmnb;
+ int msgmni;
+ int msgssz;
+ int msgtql;
+ ushort_t msgseg;
+};
+
+/*
+ * semaphore-related definitions.
+ */
+#define LX_GETPID 11
+#define LX_GETVAL 12
+#define LX_GETALL 13
+#define LX_GETNCNT 14
+#define LX_GETZCNT 15
+#define LX_SETVAL 16
+#define LX_SETALL 17
+#define LX_SEM_STAT 18
+#define LX_SEM_INFO 19
+#define LX_SEM_UNDO 0x1000
+#define LX_SEMVMX 32767
+
+struct lx_semid_ds {
+ struct lx_ipc_perm sem_perm;
+ time_t sem_otime;
+ ulong_t _unused1;
+ time_t sem_ctime;
+ ulong_t _unused2;
+ ulong_t sem_nsems;
+ ulong_t _unused3;
+ ulong_t _unused4;
+};
+
+struct lx_seminfo {
+ int semmap;
+ int semmni;
+ int semmns;
+ int semmnu;
+ int semmsl;
+ int semopm;
+ int semume;
+ int semusz;
+ int semvmx;
+ int semaem;
+};
+
+union lx_semun {
+ int val;
+ struct lx_semid_ds *semds;
+ ushort_t *sems;
+ struct lx_seminfo *info;
+ uintptr_t dummy;
+};
+
+/*
+ * shm-related definitions
+ */
+#define LX_SHM_LOCKED 02000
+#define LX_SHM_RDONLY 010000
+#define LX_SHM_RND 020000
+#define LX_SHM_REMAP 040000
+
+#define LX_SHM_LOCK 11
+#define LX_SHM_UNLOCK 12
+#define LX_SHM_STAT 13
+#define LX_SHM_INFO 14
+
+struct lx_shmid_ds {
+ struct lx_ipc_perm shm_perm;
+ size_t shm_segsz;
+ time_t shm_atime;
+#if defined(_ILP32)
+ ulong_t _unused1;
+#endif
+ time_t shm_dtime;
+#if defined(_ILP32)
+ ulong_t _unused2;
+#endif
+ time_t shm_ctime;
+#if defined(_ILP32)
+ ulong_t _unused3;
+#endif
+ pid_t shm_cpid;
+ pid_t shm_lpid;
+ ushort_t shm_nattch;
+ ulong_t _unused4;
+ ulong_t _unused5;
+};
+
+struct lx_shm_info {
+ int used_ids;
+ ulong_t shm_tot;
+ ulong_t shm_rss;
+ ulong_t shm_swp;
+ ulong_t swap_attempts;
+ ulong_t swap_successes;
+};
+
+struct lx_shminfo {
+ ulong_t shmmax;
+ ulong_t shmmin;
+ ulong_t shmmni;
+ ulong_t shmseg;
+ ulong_t shmall;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LX_SYSV_IPC_H */
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_thread.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_thread.h
new file mode 100644
index 0000000000..0a17705dd1
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_thread.h
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc
+ */
+
+#ifndef _SYS_LX_THREAD_H
+#define _SYS_LX_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/lx_signal.h>
+#include <thread.h>
+
+typedef enum lx_exit_type {
+ LX_ET_NONE = 0,
+ LX_ET_EXIT,
+ LX_ET_EXIT_GROUP
+} lx_exit_type_t;
+
+typedef struct lx_tsd {
+ /* per-thread flag set on parent vfork, cleared on thread resume */
+ int lxtsd_is_vforked;
+ lx_exit_type_t lxtsd_exit;
+ int lxtsd_exit_status;
+ ucontext_t lxtsd_exit_context;
+
+ /*
+ * If this value is non-zero, we use it in lx_sigdeliver() to represent
+ * the in-use extent of the Linux (i.e. BRAND) stack for this thread.
+ * Access to this value must be protected by _sigoff()/_sigon().
+ */
+ uintptr_t lxtsd_lx_sp;
+
+ /*
+ * Alternate stack for Linux sigaltstack emulation:
+ */
+ lx_stack_t lxtsd_sigaltstack;
+
+ void *lxtsd_clone_state;
+
+ lx_sigbackup_t *lxtsd_sigbackup;
+} lx_tsd_t;
+
+extern thread_key_t lx_tsd_key;
+
+extern void lx_swap_gs(long, long *);
+
+extern void lx_exit_common(void) __NORETURN;
+
+extern lx_tsd_t *lx_get_tsd(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LX_THREAD_H */
diff --git a/usr/src/lib/brand/lx/lx_init/Makefile b/usr/src/lib/brand/lx/lx_init/Makefile
new file mode 100644
index 0000000000..796e89f9a8
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/Makefile
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+PROG = lxinit
+
+PROG_OBJS = lxinit.o pipe_stream.o run_command.o
+LIST_OBJS = list.o
+
+OBJS = $(PROG_OBJS) \
+ $(LIST_OBJS)
+SRCS = $(PROG_OBJS:%.o=%.c) \
+ $(LIST_OBJS:%.o=$(SRC)/common/list/%.c)
+
+all: $(PROG)
+
+include ../Makefile.lx
+include $(SRC)/cmd/Makefile.cmd
+
+# override the install directory
+ROOTBIN = $(ROOTBRANDDIR)
+CLOBBERFILES = $(OBJS) $(ROOTPROG)
+
+UTSBASE = $(SRC)/uts
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(UTSBASE)/common/brand/lx
+LDLIBS += -lzonecfg -lipadm -lsocket -linetutil -lnsl -lcmdutils -ldhcpagent
+
+.KEEP_STATE:
+
+install: all $(ROOTPROG)
+
+clean:
+ $(RM) $(PROG) $(OBJS)
+
+lint: lint_PROG lint_SRCS
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.o: $(SRC)/common/list/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/lib/brand/lx/lx_init/lxinit.c b/usr/src/lib/brand/lx/lx_init/lxinit.c
new file mode 100644
index 0000000000..8d1b8d2376
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/lxinit.c
@@ -0,0 +1,872 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * lxinit performs zone-specific initialization prior to handing control to the
+ * guest Linux init. This primarily consists of:
+ *
+ * - Starting ipmgmtd
+ * - Configuring network interfaces
+ * - Adding a default route
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <net/if.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stropts.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/varargs.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <locale.h>
+#include <libcmdutils.h>
+
+#include <netinet/dhcp.h>
+#include <dhcpagent_util.h>
+#include <dhcpagent_ipc.h>
+
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <libipadm.h>
+#include <libzonecfg.h>
+#include <libinetutil.h>
+#include <sys/lx_brand.h>
+
+#include "run_command.h"
+
+static void lxi_err(char *msg, ...) __NORETURN;
+static void lxi_err(char *msg, ...);
+
+#define IPMGMTD_PATH "/lib/inet/ipmgmtd"
+#define IN_NDPD_PATH "/usr/lib/inet/in.ndpd"
+
+#define PREFIX_LOG_WARN "lx_init warn: "
+#define PREFIX_LOG_ERR "lx_init err: "
+
+#define RTMBUFSZ (sizeof (struct rt_msghdr) + \
+ (3 * sizeof (struct sockaddr_in)))
+
+ipadm_handle_t iph;
+
+static void
+lxi_err(char *msg, ...)
+{
+ char buf[1024];
+ int len;
+ va_list ap;
+
+ va_start(ap, msg);
+ /*LINTED*/
+ len = vsnprintf(buf, sizeof (buf), msg, ap);
+ va_end(ap);
+
+ (void) write(1, PREFIX_LOG_ERR, strlen(PREFIX_LOG_ERR));
+ (void) write(1, buf, len);
+ (void) write(1, "\n", 1);
+
+ /*
+ * Since a non-zero exit will cause the zone to reboot, a pause here
+ * will prevent a mis-configured zone from spinning in a reboot loop.
+ */
+ pause();
+ exit(1);
+ /*NOTREACHED*/
+}
+
+static void
+lxi_warn(char *msg, ...)
+{
+ char buf[1024];
+ int len;
+ va_list ap;
+
+ va_start(ap, msg);
+ /*LINTED*/
+ len = vsnprintf(buf, sizeof (buf), msg, ap);
+ va_end(ap);
+
+ (void) write(1, PREFIX_LOG_WARN, strlen(PREFIX_LOG_WARN));
+ (void) write(1, buf, len);
+ (void) write(1, "\n", 1);
+}
+
+static void
+lxi_log_open()
+{
+ int fd = open("/dev/console", O_WRONLY);
+
+ if (fd < 0) {
+ /* hard to log at this point... */
+ exit(1);
+ } else if (fd != 1) {
+ /*
+ * Use stdout as the log fd. Init should start with no files
+ * open, so we should be required to perform this relocation
+ * every time.
+ */
+ if (dup2(fd, 1) != 1) {
+ exit(1);
+ }
+ }
+}
+
+static void
+lxi_log_close()
+{
+ (void) close(0);
+ (void) close(1);
+}
+
+static zone_dochandle_t
+lxi_config_open()
+{
+ zoneid_t zoneid;
+ char zonename[ZONENAME_MAX];
+ zone_dochandle_t handle;
+ zone_iptype_t iptype;
+ int res;
+
+ zoneid = getzoneid();
+ if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) < 0) {
+ lxi_err("could not determine zone name");
+ }
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ lxi_err("internal libzonecfg.so.1 error", 0);
+
+ if ((res = zonecfg_get_handle(zonename, handle)) != Z_OK) {
+ zonecfg_fini_handle(handle);
+ lxi_err("could not locate zone config %d", res);
+ }
+
+ /*
+ * Only exclusive stack is supported.
+ */
+ if (zonecfg_get_iptype(handle, &iptype) != Z_OK ||
+ iptype != ZS_EXCLUSIVE) {
+ zonecfg_fini_handle(handle);
+ lxi_err("lx zones do not support shared IP stacks");
+ }
+
+ return (handle);
+
+}
+
+static int
+zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
+ const char **result)
+{
+ while (attrs != NULL) {
+ if (strncmp(attrs->zone_res_attr_name, name,
+ MAXNAMELEN) == 0) {
+ *result = attrs->zone_res_attr_value;
+ return (0);
+ }
+ attrs = attrs->zone_res_attr_next;
+ }
+ return (-1);
+}
+
+void
+lxi_svc_start(char *name, char *path, char *fmri)
+{
+ pid_t pid;
+ int status;
+ char *const argv[] = {
+ name,
+ NULL
+ };
+ char *const envp[] = {
+ fmri,
+ NULL
+ };
+
+ pid = fork();
+ if (pid == -1) {
+ lxi_err("fork() failed: %s", strerror(errno));
+ }
+
+ if (pid == 0) {
+ /* child */
+ const char *zroot = zone_get_nroot();
+ char cmd[MAXPATHLEN];
+
+ /*
+ * Construct the full path to the binary, including the native
+ * system root (e.g. "/native") if in use for this zone:
+ */
+ (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
+ zroot : "", path);
+
+ execve(cmd, argv, envp);
+
+ lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
+ /* NOTREACHED */
+ }
+
+ /* parent */
+ while (wait(&status) != pid) {
+ /* EMPTY */;
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ lxi_err("%s[%d] exited: %d", name,
+ (int)pid, WEXITSTATUS(status));
+ }
+ } else if (WIFSIGNALED(status)) {
+ lxi_err("%s[%d] died on signal: %d", name,
+ (int)pid, WTERMSIG(status));
+ } else {
+ lxi_err("%s[%d] failed in unknown way", name,
+ (int)pid);
+ }
+}
+
+void
+lxi_net_ipmgmtd_start()
+{
+ lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
+ "SMF_FMRI=svc:/network/ip-interface-management:default");
+}
+
+void
+lxi_net_ndpd_start()
+{
+ lxi_svc_start("in.ndpd", IN_NDPD_PATH,
+ "SMF_FMRI=svc:/network/routing/ndp:default");
+}
+
+
+static void
+lxi_net_ipadm_open()
+{
+ ipadm_status_t status;
+
+ if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) {
+ lxi_err("Error opening ipadm handle: %s",
+ ipadm_status2str(status));
+ }
+}
+
+static void
+lxi_net_ipadm_close()
+{
+ ipadm_close(iph);
+}
+
+void
+lxi_net_plumb(const char *iface)
+{
+ ipadm_status_t status;
+ char ifbuf[LIFNAMSIZ];
+
+ /* ipadm_create_if stomps on ifbuf, so create a copy: */
+ (void) strncpy(ifbuf, iface, sizeof (ifbuf));
+
+ if ((status = ipadm_create_if(iph, ifbuf, AF_INET, IPADM_OPT_ACTIVE))
+ != IPADM_SUCCESS) {
+ lxi_err("ipadm_create_if error %d: %s/v4: %s",
+ status, iface, ipadm_status2str(status));
+ }
+
+ if ((status = ipadm_create_if(iph, ifbuf, AF_INET6, IPADM_OPT_ACTIVE))
+ != IPADM_SUCCESS) {
+ lxi_err("ipadm_create_if error %d: %s/v6: %s",
+ status, iface, ipadm_status2str(status));
+ }
+}
+
+static int
+lxi_getif(int af, char *iface, int len, boolean_t first_ipv4_configured)
+{
+ struct lifreq lifr;
+ int s = socket(af, SOCK_DGRAM, 0);
+ if (s < 0) {
+ lxi_warn("socket error %d: bringing up %s: %s",
+ errno, iface, strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * We need a new logical interface for every IP address we add, except
+ * for the very first IPv4 address.
+ */
+ if (af == AF_INET6 || first_ipv4_configured) {
+ (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
+ (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
+ if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
+ if (close(s) != 0) {
+ lxi_warn("failed to close socket: %s\n",
+ strerror(errno));
+ }
+ return (-1);
+ }
+ (void) strncpy(iface, lifr.lifr_name, len);
+ }
+
+ if (close(s) != 0) {
+ lxi_warn("failed to close socket: %s\n",
+ strerror(errno));
+ }
+ return (0);
+}
+
+static int
+lxi_iface_ip(const char *origiface, const char *addr,
+ boolean_t *first_ipv4_configured)
+{
+ static int addrnum = 0;
+ ipadm_status_t status;
+ ipadm_addrobj_t ipaddr = NULL;
+ char iface[LIFNAMSIZ];
+ char aobjname[IPADM_AOBJSIZ];
+ int af, err = 0;
+
+ (void) strncpy(iface, origiface, sizeof (iface));
+
+ af = strstr(addr, ":") == NULL ? AF_INET : AF_INET6;
+ if (lxi_getif(af, iface, sizeof (iface), *first_ipv4_configured) != 0) {
+ lxi_warn("failed to create new logical interface "
+ "on %s: %s", origiface, strerror(errno));
+ return (-1);
+ }
+
+ (void) snprintf(aobjname, IPADM_AOBJSIZ, "%s/addr%d", iface,
+ addrnum++);
+
+ if ((status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname,
+ &ipaddr)) != IPADM_SUCCESS) {
+ lxi_warn("ipadm_create_addrobj error %d: addr %s, "
+ "interface %s: %s\n", status, addr, iface,
+ ipadm_status2str(status));
+ return (-2);
+ }
+
+ if ((status = ipadm_set_addr(ipaddr, addr, AF_UNSPEC))
+ != IPADM_SUCCESS) {
+ lxi_warn("ipadm_set_addr error %d: addr %s"
+ ", interface %s: %s\n", status, addr,
+ iface, ipadm_status2str(status));
+ err = -3;
+ goto done;
+ }
+
+ if ((status = ipadm_create_addr(iph, ipaddr,
+ IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
+ lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
+ ipadm_status2str(status));
+ err = -4;
+ goto done;
+ }
+
+ if (af == AF_INET) {
+ *first_ipv4_configured = B_TRUE;
+ }
+
+done:
+ ipadm_destroy_addrobj(ipaddr);
+ return (err);
+}
+
+static int
+lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
+{
+ dhcp_ipc_request_t *dhcpreq = NULL;
+ dhcp_ipc_reply_t *dhcpreply = NULL;
+ int err = 0, timeout = 5;
+ char iface[LIFNAMSIZ];
+
+ (void) strncpy(iface, origiface, sizeof (iface));
+
+ if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
+ != 0) {
+ lxi_warn("failed to create new logical interface "
+ "on %s: %s", origiface, strerror(errno));
+ return (-1);
+ }
+
+ if (dhcp_start_agent(timeout) != 0) {
+ lxi_err("Failed to start dhcpagent\n");
+ /* NOTREACHED */
+ }
+
+ dhcpreq = dhcp_ipc_alloc_request(DHCP_START, iface,
+ NULL, 0, DHCP_TYPE_NONE);
+ if (dhcpreq == NULL) {
+ lxi_warn("Unable to allocate memory "
+ "to start DHCP on %s\n", iface);
+ return (-1);
+ }
+
+ err = dhcp_ipc_make_request(dhcpreq, &dhcpreply, timeout);
+ if (err != 0) {
+ free(dhcpreq);
+ lxi_warn("Failed to start DHCP on %s: %s\n", iface,
+ dhcp_ipc_strerror(err));
+ return (-1);
+ }
+ err = dhcpreply->return_code;
+ if (err != 0) {
+ lxi_warn("Failed to start DHCP on %s: %s\n", iface,
+ dhcp_ipc_strerror(err));
+ goto done;
+ }
+
+ *first_ipv4_configured = B_TRUE;
+
+done:
+ free(dhcpreq);
+ free(dhcpreply);
+ return (err);
+}
+
+/*
+ * Initialize an IPv6 link-local address on a given interface
+ */
+static int
+lxi_iface_ipv6_link_local(const char *iface)
+{
+ struct lifreq lifr;
+ int s;
+
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s == -1) {
+ lxi_warn("socket error %d: bringing up %s: %s",
+ errno, iface, strerror(errno));
+ }
+
+ (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
+ if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
+ lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
+ errno, iface, strerror(errno));
+ return (-1);
+ }
+
+ lifr.lifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
+ lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
+ errno, iface, strerror(errno));
+ return (-1);
+ }
+
+ (void) close(s);
+ return (0);
+}
+
+static int
+lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
+ const char *gwaddr)
+{
+ int idx, len, sockfd;
+ char rtbuf[RTMBUFSZ];
+ struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
+ struct sockaddr_in *dst_sin = (struct sockaddr_in *)
+ (rtbuf + sizeof (struct rt_msghdr));
+ struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
+ struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
+
+ (void) bzero(rtm, RTMBUFSZ);
+ rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
+ rtm->rtm_msglen = sizeof (rtbuf);
+ rtm->rtm_pid = getpid();
+ rtm->rtm_type = RTM_ADD;
+ rtm->rtm_version = RTM_VERSION;
+
+
+ /*
+ * The destination and netmask components have already been zeroed,
+ * which represents the default gateway. If we were passed a more
+ * specific destination network, use that instead.
+ */
+ dst_sin->sin_family = AF_INET;
+ netmask_sin->sin_family = AF_INET;
+ if (dst != NULL) {
+ struct sockaddr *mask = (struct sockaddr *)netmask_sin;
+
+ if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
+ plen2mask(dstpfx, AF_INET, mask) != 0) {
+ lxi_warn("bad destination network %s/%d: %s", dst,
+ dstpfx, strerror(errno));
+ return (-1);
+ }
+ }
+
+ if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
+ lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
+ return (-1);
+ }
+
+ if (iface != NULL) {
+ if ((idx = if_nametoindex(iface)) == 0) {
+ lxi_warn("unable to get interface index for %s: %s\n",
+ iface, strerror(errno));
+ return (-1);
+ }
+ rtm->rtm_index = idx;
+ }
+
+ if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
+ return (-1);
+ }
+
+ if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
+ lxi_warn("could not write rtmsg: %s", strerror(errno));
+ close(sockfd);
+ return (-1);
+ } else if (len < rtm->rtm_msglen) {
+ lxi_warn("write() rtmsg incomplete");
+ close(sockfd);
+ return (-1);
+ }
+
+ close(sockfd);
+ return (0);
+}
+
+static void
+lxi_net_loopback()
+{
+ const char *iface = "lo0";
+ boolean_t first_ipv4_configured = B_FALSE;
+
+ lxi_net_plumb(iface);
+ (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
+ (void) lxi_iface_ipv6_link_local(iface);
+}
+
+
+/*
+ * This function is used when the "ips" property doesn't exist in a zone's
+ * configuration. It may be an older configuration, so we should search for
+ * "ip" and "netmask" and convert them into the new format.
+ */
+static int
+lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
+ char *cidraddr, int len)
+{
+
+ const char *netmask;
+ int prefixlen;
+ struct sockaddr_in mask_sin;
+
+ lxi_warn("Could not find \"ips\" property for zone. Looking "
+ "for older \"ip\" and \"netmask\" properties, instead.");
+
+ if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
+ return (-1);
+ }
+
+ if (strcmp(*ipaddrs, "dhcp") == 0) {
+ return (0);
+ }
+
+ if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
+ lxi_err("could not find netmask for interface");
+ /* NOTREACHED */
+ }
+
+ /* Convert the netmask to a number */
+ mask_sin.sin_family = AF_INET;
+ if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
+ lxi_err("invalid netmask address: %s\n",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ prefixlen = mask2plen((struct sockaddr *)&mask_sin);
+
+ /*
+ * Write out the IP address in the new format and use
+ * that instead
+ */
+ (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
+
+ *ipaddrs = cidraddr;
+ return (0);
+}
+
+static void
+lxi_net_setup(zone_dochandle_t handle)
+{
+ struct zone_nwiftab lookup;
+ boolean_t do_addrconf = B_FALSE;
+
+ if (zonecfg_setnwifent(handle) != Z_OK)
+ return;
+ while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
+ const char *iface = lookup.zone_nwif_physical;
+ struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
+ const char *ipaddrs, *primary, *gateway;
+ char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
+ *ipaddr, *tmp, *lasts;
+ boolean_t first_ipv4_configured = B_FALSE;
+ boolean_t *ficp = &first_ipv4_configured;
+
+ lxi_net_plumb(iface);
+ if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
+ lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
+ lxi_warn("Could not find a valid network configuration "
+ "for the %s interface", iface);
+ continue;
+ }
+
+ if (lxi_iface_ipv6_link_local(iface) != 0) {
+ lxi_warn("unable to bring up link-local address on "
+ "interface %s", iface);
+ }
+
+ /*
+ * If we're going to be doing DHCP, we have to do it first since
+ * dhcpagent doesn't like to operate on non-zero logical
+ * interfaces.
+ */
+ if (strstr(ipaddrs, "dhcp") != NULL &&
+ lxi_iface_dhcp(iface, ficp) != 0) {
+ lxi_warn("Failed to start DHCP on %s\n", iface);
+ }
+
+ /*
+ * Copy the ipaddrs string, since strtok_r will write NUL
+ * characters into it.
+ */
+ (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
+ tmp = ipaddrs_copy;
+
+ /*
+ * Iterate over each IP and then set it up on the interface.
+ */
+ while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
+ tmp = NULL;
+ if (strcmp(ipaddr, "addrconf") == 0) {
+ do_addrconf = B_TRUE;
+ } else if (strcmp(ipaddr, "dhcp") == 0) {
+ continue;
+ } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
+ lxi_warn("Unable to add new IP address (%s) "
+ "to interface %s", ipaddr, iface);
+ }
+ }
+
+ if (zone_find_attr(attrs, "primary", &primary) == 0 &&
+ strncmp(primary, "true", MAXNAMELEN) == 0 &&
+ zone_find_attr(attrs, "gateway", &gateway) == 0) {
+ lxi_iface_gateway(iface, NULL, 0, gateway);
+ }
+ }
+
+ if (do_addrconf) {
+ lxi_net_ndpd_start();
+ }
+
+ (void) zonecfg_endnwifent(handle);
+}
+
+static void
+lxi_net_static_route(const char *line)
+{
+ /*
+ * Each static route line is a string of the form:
+ *
+ * "10.77.77.2|10.1.1.0/24|false"
+ *
+ * i.e. gateway address, destination network, and whether this is
+ * a "link local" route or a next hop route.
+ */
+ custr_t *cu = NULL;
+ char *gw = NULL, *dst = NULL;
+ int pfx = -1;
+ int i;
+
+ if (custr_alloc(&cu) != 0) {
+ lxi_err("custr_alloc failure");
+ }
+
+ for (i = 0; line[i] != '\0'; i++) {
+ if (gw == NULL) {
+ if (line[i] == '|') {
+ if ((gw = strdup(custr_cstr(cu))) == NULL) {
+ lxi_err("strdup failure");
+ }
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (dst == NULL) {
+ if (line[i] == '/') {
+ if ((dst = strdup(custr_cstr(cu))) == NULL) {
+ lxi_err("strdup failure");
+ }
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (pfx == -1) {
+ if (line[i] == '|') {
+ pfx = atoi(custr_cstr(cu));
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+
+ /*
+ * We currently only support "next hop" routes, so ensure that
+ * "linklocal" is false:
+ */
+ if (strcmp(custr_cstr(cu), "false") != 0) {
+ lxi_warn("invalid static route: %s", line);
+ }
+
+ if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
+ lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
+ }
+
+ custr_free(cu);
+ free(gw);
+ free(dst);
+}
+
+static void
+lxi_net_static_routes(void)
+{
+ const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
+ char *const argv[] = { "routeinfo", NULL };
+ char *const envp[] = { NULL };
+ int code;
+ struct stat st;
+ char errbuf[512];
+
+ if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
+ /*
+ * This binary is (potentially) shipped from another
+ * consolidation. If it does not exist, then the platform does
+ * not currently support static routes for LX-branded zones.
+ */
+ return;
+ }
+
+ /*
+ * Run the command, firing the callback for each line that it
+ * outputs. When this function returns, static route processing
+ * is complete.
+ */
+ if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
+ lxi_net_static_route, &code) != 0 || code != 0) {
+ lxi_err("failed to run \"%s\": %s", cmd, errbuf);
+ }
+}
+
+static void
+lxi_config_close(zone_dochandle_t handle)
+{
+ zonecfg_fini_handle(handle);
+}
+
+static void
+lxi_init_exec(char **argv)
+{
+ const char *cmd = "/sbin/init";
+ char *const envp[] = { "container=zone", NULL };
+ int e;
+
+ argv[0] = "init";
+
+ /*
+ * systemd uses the 'container' env var to determine it is running
+ * inside a container. It only supports a few well-known types and
+ * treats anything else as 'other' but this is enough to make it
+ * behave better inside a zone. See 'detect_container' in systemd.
+ */
+ execve(cmd, argv, envp);
+ e = errno;
+
+ /*
+ * Because stdout was closed prior to exec, it must be opened again in
+ * the face of failure to log the error.
+ */
+ lxi_log_open();
+ lxi_err("execve(%s) failed: %s", cmd, strerror(e));
+}
+
+/*ARGSUSED*/
+int
+main(int argc, char *argv[])
+{
+ zone_dochandle_t handle;
+
+ lxi_log_open();
+
+ lxi_net_ipmgmtd_start();
+ lxi_net_ipadm_open();
+
+ handle = lxi_config_open();
+ lxi_net_loopback();
+ lxi_net_setup(handle);
+ lxi_config_close(handle);
+
+ lxi_net_static_routes();
+
+ lxi_net_ipadm_close();
+
+ lxi_log_close();
+
+ lxi_init_exec(argv);
+
+ /* NOTREACHED */
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_init/pipe_stream.c b/usr/src/lib/brand/lx/lx_init/pipe_stream.c
new file mode 100644
index 0000000000..8f06a07906
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/pipe_stream.c
@@ -0,0 +1,326 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <port.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <sys/list.h>
+
+#include "pipe_stream.h"
+
+struct pipe_stream {
+ pipe_stream_loop_t *pis_loop;
+
+ boolean_t pis_finished;
+ boolean_t pis_associated;
+
+ void *pis_arg0;
+ void *pis_arg1;
+
+ int pis_fd_write;
+ int pis_fd_read;
+ list_node_t pis_linkage;
+};
+
+struct pipe_stream_loop {
+ int psl_port;
+
+ uint8_t *psl_buf;
+ size_t psl_buf_cap;
+ size_t psl_buf_occ;
+
+ list_t psl_pipes;
+
+ pipe_stream_data_cb *psl_cb_data;
+ pipe_stream_eof_cb *psl_cb_eof;
+ pipe_stream_error_cb *psl_cb_error;
+};
+
+
+int
+pipe_stream_loop_fini(pipe_stream_loop_t *psl)
+{
+ if (psl == NULL) {
+ return (0);
+ }
+
+ VERIFY0(close(psl->psl_port));
+
+ while (!list_is_empty(&psl->psl_pipes)) {
+ pipe_stream_fini(list_head(&psl->psl_pipes));
+ }
+
+ list_destroy(&psl->psl_pipes);
+ free(psl);
+
+ return (0);
+}
+
+int
+pipe_stream_loop_init(pipe_stream_loop_t **pslp, size_t bufsize,
+ pipe_stream_data_cb *data_cb, pipe_stream_eof_cb *eof_cb,
+ pipe_stream_error_cb *error_cb)
+{
+ pipe_stream_loop_t *psl;
+
+ if ((psl = calloc(1, sizeof (*psl))) == NULL) {
+ return (-1);
+ }
+
+ psl->psl_buf_cap = bufsize;
+ psl->psl_buf_occ = 0;
+ if ((psl->psl_buf = calloc(1, bufsize)) == NULL) {
+ free(psl);
+ return (-1);
+ }
+
+ if ((psl->psl_port = port_create()) == -1) {
+ free(psl->psl_buf);
+ free(psl);
+ return (-1);
+ }
+
+ psl->psl_cb_data = data_cb;
+ psl->psl_cb_eof = eof_cb;
+ psl->psl_cb_error = error_cb;
+
+ list_create(&psl->psl_pipes, sizeof (pipe_stream_t),
+ offsetof(pipe_stream_t, pis_linkage));
+
+ *pslp = psl;
+ return (0);
+}
+
+boolean_t
+pipe_stream_loop_should_run(pipe_stream_loop_t *psl)
+{
+ pipe_stream_t *pis;
+
+ for (pis = list_head(&psl->psl_pipes); pis != NULL;
+ pis = list_next(&psl->psl_pipes, pis)) {
+ if (!pis->pis_finished) {
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+int
+pipe_stream_loop_run(pipe_stream_loop_t *psl)
+{
+ pipe_stream_t *pis;
+ port_event_t pev;
+ ssize_t sz;
+
+ for (pis = list_head(&psl->psl_pipes); pis != NULL;
+ pis = list_next(&psl->psl_pipes, pis)) {
+ if (pis->pis_finished || pis->pis_associated) {
+ /*
+ * Skip streams that are already finished, as well as
+ * those that have already been associated with the
+ * port.
+ */
+ continue;
+ }
+
+ if (port_associate(psl->psl_port, PORT_SOURCE_FD,
+ pis->pis_fd_read, POLLIN, pis) != 0) {
+ return (-1);
+ }
+ }
+
+again:
+ if (port_get(psl->psl_port, &pev, NULL) != 0) {
+ switch (errno) {
+ case ETIME:
+ /*
+ * Timeout expired; return to caller.
+ */
+ return (0);
+
+ case EINTR:
+ /*
+ * Interrupted by signal. Try again.
+ */
+ goto again;
+
+ default:
+ return (-1);
+ }
+ }
+
+ VERIFY(pev.portev_source == PORT_SOURCE_FD);
+ pis = (pipe_stream_t *)pev.portev_user;
+ VERIFY((int)pev.portev_object == pis->pis_fd_read);
+ pis->pis_associated = B_FALSE;
+
+read_again:
+ if ((sz = read(pis->pis_fd_read, psl->psl_buf,
+ psl->psl_buf_cap)) == -1) {
+ if (errno == EINTR) {
+ goto read_again;
+ }
+
+ if (psl->psl_cb_error != NULL) {
+ psl->psl_cb_error(errno, pis->pis_arg0, pis->pis_arg1);
+ }
+
+ VERIFY0(close(pis->pis_fd_read));
+ pis->pis_fd_read = -1;
+ pis->pis_finished = B_TRUE;
+ }
+ psl->psl_buf_occ = sz;
+
+ if (sz == 0) {
+ /*
+ * Stream EOF.
+ */
+ pis->pis_finished = B_TRUE;
+ VERIFY0(close(pis->pis_fd_read));
+ pis->pis_fd_read = -1;
+ if (psl->psl_cb_eof != NULL) {
+ psl->psl_cb_eof(pis->pis_arg0, pis->pis_arg1);
+ }
+ return (0);
+ }
+
+ if (psl->psl_cb_data != NULL) {
+ int cbr = psl->psl_cb_data(psl->psl_buf, psl->psl_buf_occ,
+ pis->pis_arg0, pis->pis_arg1);
+
+ if (cbr != 0) {
+ /*
+ * Callback failure: close file descriptor.
+ */
+ pis->pis_finished = B_TRUE;
+ VERIFY0(close(pis->pis_fd_read));
+ pis->pis_fd_read = -1;
+ if (psl->psl_cb_eof != NULL) {
+ psl->psl_cb_eof(pis->pis_arg0, pis->pis_arg1);
+ }
+ }
+
+ return (0);
+ }
+
+ return (0);
+}
+
+int
+pipe_stream_init(pipe_stream_loop_t *psl, pipe_stream_t **pisp, void *arg0,
+ void *arg1)
+{
+ int e = 0;
+ pipe_stream_t *pis;
+ int fds[2] = { -1, -1 };
+
+ if ((pis = calloc(1, sizeof (*pis))) == NULL) {
+ return (-1);
+ }
+
+ if (pipe(fds) != 0) {
+ e = errno;
+ goto fail;
+ }
+
+ pis->pis_fd_read = fds[0];
+ pis->pis_fd_write = fds[1];
+
+ pis->pis_arg0 = arg0;
+ pis->pis_arg1 = arg1;
+
+ pis->pis_finished = B_FALSE;
+ pis->pis_associated = B_FALSE;
+
+ pis->pis_loop = psl;
+ list_insert_tail(&psl->psl_pipes, pis);
+
+ *pisp = pis;
+ return (0);
+
+fail:
+ if (fds[0] != -1) {
+ VERIFY0(close(fds[0]));
+ }
+ if (fds[1] != -1) {
+ VERIFY0(close(fds[1]));
+ }
+ free(pis);
+ errno = e;
+ return (-1);
+}
+
+int
+pipe_stream_fini(pipe_stream_t *pis)
+{
+ if (pis == NULL) {
+ return (0);
+ }
+
+ if (pis->pis_fd_read != -1) {
+ VERIFY0(close(pis->pis_fd_read));
+ }
+ if (pis->pis_fd_write != -1) {
+ VERIFY0(close(pis->pis_fd_write));
+ }
+
+ list_remove(&pis->pis_loop->psl_pipes, pis);
+
+ free(pis);
+ return (0);
+}
+
+/*
+ * Called in the parent, after forking, to close the "write" end of the pipe.
+ */
+void
+pipe_stream_parent_afterfork(pipe_stream_t *pis)
+{
+ if (pis->pis_fd_write != -1) {
+ (void) close(pis->pis_fd_write);
+ pis->pis_fd_write = -1;
+ }
+}
+
+/*
+ * Called in the child, after forking, to close the "read" end of the
+ * pipe, and to dup the file descriptor into the right place.
+ */
+int
+pipe_stream_child_afterfork(pipe_stream_t *pis, int dup_to)
+{
+ int e = 0;
+
+ if (dup_to != -1) {
+ if (dup2(pis->pis_fd_write, dup_to) == -1) {
+ e = errno;
+ }
+ VERIFY0(close(pis->pis_fd_write));
+ pis->pis_fd_write = dup_to;
+ }
+
+ (void) close(pis->pis_fd_read);
+ pis->pis_fd_read = -1;
+
+ errno = e;
+ return (e == 0 ? 0 : -1);
+}
diff --git a/usr/src/lib/brand/lx/lx_init/pipe_stream.h b/usr/src/lib/brand/lx/lx_init/pipe_stream.h
new file mode 100644
index 0000000000..140ef18f8c
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/pipe_stream.h
@@ -0,0 +1,48 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _PIPE_STREAM_H
+#define _PIPE_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int pipe_stream_data_cb(const uint8_t *, size_t, void *, void *);
+typedef void pipe_stream_eof_cb(void *, void *);
+typedef void pipe_stream_error_cb(int, void *, void *);
+
+typedef struct pipe_stream pipe_stream_t;
+typedef struct pipe_stream_loop pipe_stream_loop_t;
+
+extern int pipe_stream_loop_fini(pipe_stream_loop_t *);
+extern int pipe_stream_loop_init(pipe_stream_loop_t **, size_t,
+ pipe_stream_data_cb *, pipe_stream_eof_cb *, pipe_stream_error_cb *);
+
+extern int pipe_stream_init(pipe_stream_loop_t *, pipe_stream_t **, void *,
+ void *);
+extern int pipe_stream_fini(pipe_stream_t *);
+
+extern void pipe_stream_parent_afterfork(pipe_stream_t *);
+extern int pipe_stream_child_afterfork(pipe_stream_t *, int);
+
+extern boolean_t pipe_stream_loop_should_run(pipe_stream_loop_t *);
+extern int pipe_stream_loop_run(pipe_stream_loop_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PIPE_STREAM_H */
diff --git a/usr/src/lib/brand/lx/lx_init/run_command.c b/usr/src/lib/brand/lx/lx_init/run_command.c
new file mode 100644
index 0000000000..ad00b60482
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/run_command.c
@@ -0,0 +1,281 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wait.h>
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <libcmdutils.h>
+
+#include "run_command.h"
+#include "pipe_stream.h"
+
+typedef struct cmd {
+ int cmd_pid;
+ int cmd_wstatus;
+ pipe_stream_t *cmd_pipe[2];
+ custr_t *cmd_err;
+ custr_t *cmd_out;
+ run_command_line_cb *cmd_func;
+ boolean_t cmd_cancel;
+} cmd_t;
+
+static int cb_data(const uint8_t *, size_t, void *, void *);
+static void cb_eof(void *, void *);
+static void cb_error(int, void *, void *);
+
+void
+post_error(cmd_t *cmd, const char *estr)
+{
+ if (cmd->cmd_cancel) {
+ return;
+ }
+ cmd->cmd_cancel = B_TRUE;
+
+ custr_reset(cmd->cmd_err);
+ (void) custr_append(cmd->cmd_err, estr);
+}
+
+int
+run_command(const char *path, char *const argv[], char *const envp[],
+ char *errbuf, size_t errlen, run_command_line_cb *func, int *status)
+{
+ pipe_stream_loop_t *psl = NULL;
+ int e = 0;
+ cmd_t cmd;
+ pid_t wpid;
+
+ bzero(&cmd, sizeof (cmd));
+
+ cmd.cmd_func = func;
+
+ /*
+ * Allocate string buffers for stdout line buffering and error
+ * messages:
+ */
+ if (custr_alloc_buf(&cmd.cmd_err, errbuf, errlen) != 0 ||
+ custr_alloc(&cmd.cmd_out) != 0) {
+ e = errno;
+ goto out;
+ }
+
+ /*
+ * Initialise pipe stream event loop:
+ */
+ if (pipe_stream_loop_init(&psl, 256, cb_data, cb_eof, cb_error) != 0) {
+ e = errno;
+ post_error(&cmd, "could not init pipe stream loop");
+ goto out;
+ }
+
+ /*
+ * Create pipe streams for stdout and stderr communication with
+ * child process:
+ */
+ if (pipe_stream_init(psl, &cmd.cmd_pipe[0], &cmd,
+ (void *)STDOUT_FILENO) != 0 ||
+ pipe_stream_init(psl, &cmd.cmd_pipe[1], &cmd,
+ (void *)STDERR_FILENO) != 0) {
+ e = errno;
+ post_error(&cmd, "could not init pipe streams");
+ goto out;
+ }
+
+ /*
+ * Fork a child process:
+ */
+ if ((cmd.cmd_pid = fork()) == -1) {
+ e = errno;
+ post_error(&cmd, "could not fork");
+ goto out;
+ }
+
+ if (cmd.cmd_pid == 0) {
+ /*
+ * This is the child process. Clean up file descriptors, and
+ * connect stdio to the pipes we allocated:
+ */
+ VERIFY0(close(STDIN_FILENO));
+ VERIFY0(pipe_stream_child_afterfork(cmd.cmd_pipe[0],
+ STDOUT_FILENO));
+ VERIFY0(pipe_stream_child_afterfork(cmd.cmd_pipe[1],
+ STDERR_FILENO));
+ closefrom(3);
+
+ execve(path, argv, envp);
+ err(127, "exec(%s) failed", path);
+ }
+
+ /*
+ * Back in the parent. Close the remote end of the stdio pipes:
+ */
+ pipe_stream_parent_afterfork(cmd.cmd_pipe[0]);
+ pipe_stream_parent_afterfork(cmd.cmd_pipe[1]);
+
+ /*
+ * Run the pipe event loop until all streams are completely
+ * consumed:
+ */
+ while (pipe_stream_loop_should_run(psl)) {
+ if (pipe_stream_loop_run(psl) != 0) {
+ e = errno;
+ post_error(&cmd, "pipe stream loop run failure");
+ goto out;
+ }
+ }
+
+ /*
+ * Collect exit status of child process:
+ */
+ while ((wpid = waitpid(cmd.cmd_pid, &cmd.cmd_wstatus, 0)) !=
+ cmd.cmd_pid) {
+ if (wpid == -1 && errno != EINTR) {
+ e = errno;
+ post_error(&cmd, "waitpid failure");
+ goto out;
+ }
+ }
+
+ /*
+ * If the child died on a signal, fail the whole operation:
+ */
+ if (WIFSIGNALED(cmd.cmd_wstatus)) {
+ e = ENXIO;
+ post_error(&cmd, "child process died on signal");
+ (void) custr_append_printf(cmd.cmd_err, " (pid %d signal %d)",
+ cmd.cmd_pid, WTERMSIG(cmd.cmd_wstatus));
+ goto out;
+ }
+
+ /*
+ * If the child did not appear to exit, fail the whole operation:
+ */
+ if (!WIFEXITED(cmd.cmd_wstatus)) {
+ e = ENXIO;
+ post_error(&cmd, "child process did not exit");
+ (void) custr_append_printf(cmd.cmd_err, " (pid %d status %x)",
+ cmd.cmd_pid, cmd.cmd_wstatus);
+ goto out;
+ }
+
+ /*
+ * Report exit status to the caller:
+ */
+ *status = WEXITSTATUS(cmd.cmd_wstatus);
+ e = 0;
+
+out:
+ VERIFY0(pipe_stream_loop_fini(psl));
+ /*
+ * Note that freeing the static error custr_t does not touch the
+ * underlying storage; we use this property to return the error
+ * message (if one exists) to the caller.
+ */
+ custr_free(cmd.cmd_err);
+ custr_free(cmd.cmd_out);
+ errno = e;
+ return (e == 0 ? 0 : -1);
+}
+
+static int
+cb_data(const uint8_t *buf, size_t sz, void *arg0, void *arg1)
+{
+ cmd_t *cmd = arg0;
+ int fd = (int)arg1;
+ unsigned int i;
+
+ if (cmd->cmd_cancel) {
+ return (-1);
+ }
+
+ switch (fd) {
+ case STDOUT_FILENO:
+ for (i = 0; i < sz; i++) {
+ if (buf[i] == '\0' || buf[i] == '\r') {
+ continue;
+ }
+
+ if (buf[i] == '\n') {
+ cmd->cmd_func(custr_cstr(cmd->cmd_out));
+ custr_reset(cmd->cmd_out);
+ continue;
+ }
+
+ if (custr_appendc(cmd->cmd_out, buf[i]) != 0) {
+ /*
+ * Failed to allocate memory; returning
+ * -1 here will abort the stream.
+ */
+ post_error(cmd, "custr_appendc failure");
+ return (-1);
+ }
+ }
+ break;
+
+ case STDERR_FILENO:
+ /*
+ * Collect as much stderr output as will fit in our static
+ * buffer.
+ */
+ for (i = 0; i < sz; i++) {
+ if (buf[i] == '\0') {
+ continue;
+ }
+
+ (void) custr_appendc(cmd->cmd_err, buf[i]);
+ }
+ break;
+
+ default:
+ abort();
+ }
+
+ return (0);
+}
+
+static void
+cb_eof(void *arg0, void *arg1)
+{
+ cmd_t *cmd = arg0;
+ int fd = (int)arg1;
+
+ if (cmd->cmd_cancel) {
+ return;
+ }
+
+ if (fd == STDOUT_FILENO && custr_len(cmd->cmd_out) > 0) {
+ cmd->cmd_func(custr_cstr(cmd->cmd_out));
+ custr_reset(cmd->cmd_out);
+ }
+}
+
+static void
+cb_error(int e, void *arg0, void *arg1)
+{
+ cmd_t *cmd = arg0;
+ int fd = (int)arg1;
+
+ if (cmd->cmd_cancel) {
+ return;
+ }
+
+ post_error(cmd, "stream read failure");
+ (void) custr_append_printf(cmd->cmd_err, " (pid %d fd %d): %s",
+ cmd->cmd_pid, fd, strerror(e));
+}
diff --git a/usr/src/lib/brand/lx/lx_init/run_command.h b/usr/src/lib/brand/lx/lx_init/run_command.h
new file mode 100644
index 0000000000..3484b265b6
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_init/run_command.h
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _RUN_COMMAND_H
+#define _RUN_COMMAND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void run_command_line_cb(const char *);
+
+extern int run_command(const char *, char *const [], char *const [], char *,
+ size_t, run_command_line_cb *, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RUN_COMMAND_H */
diff --git a/usr/src/lib/brand/lx/lx_lockd/Makefile b/usr/src/lib/brand/lx/lx_lockd/Makefile
new file mode 100644
index 0000000000..e535a30877
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_lockd/Makefile
@@ -0,0 +1,62 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+
+#
+# Copyright 2017 Joyent, Inc.
+#
+
+PROG = lx_lockd
+
+PROG_OBJS = lockd.o nfs_tbind.o
+UTIL_OBJS = thrpool.o
+
+OBJS = $(PROG_OBJS) $(UTIL_OBJS)
+SRCS = $(PROG_OBJS:%.o=%.c)
+
+all: $(PROG)
+
+include ../Makefile.lx
+include $(SRC)/cmd/Makefile.cmd
+
+# override the install directory
+ROOTBIN = $(ROOTBRANDDIR)
+CLOBBERFILES = $(OBJS) $(ROOTPROG)
+
+CPPFLAGS += -I$(SRC)/cmd/fs.d/nfs/lib
+C99MODE = $(C99_ENABLE)
+LDLIBS += -lnsl -lsocket
+
+CERRWARN += -_gcc=-Wno-parentheses
+CERRWARN += -_gcc=-Wno-uninitialized
+CERRWARN += -_gcc=-Wno-unused-function
+
+.KEEP_STATE:
+
+install: all $(ROOTPROG)
+
+clean:
+ $(RM) $(PROG) $(OBJS)
+
+lint:
+ $(LINT.c) -erroff=E_SEC_PRINTF_VAR_FMT lockd.c $(LDLIBS)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.o: $(SRC)/cmd/fs.d/nfs/lib/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/lib/brand/lx/lx_lockd/lockd.c b/usr/src/lib/brand/lx/lx_lockd/lockd.c
new file mode 100644
index 0000000000..6a80b5355c
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_lockd/lockd.c
@@ -0,0 +1,568 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * lx-brand NFS lockd (NLM) server.
+ *
+ * This code is derived from the native lockd. The original history starts
+ * from:
+ * copied from usr/src/cmd/fs.d/nfs/nfsd/nfsd.c and then s:NFS:NLM: applied
+ *
+ * On Linux 'lockd' is implemented entirely inside the kernel, whereas our
+ * native lockd support is a combination of user-level and kernel code.
+ * Unfortunately, the native lockd is unable to run in lx for several reasons:
+ * - tightly bound to SMF
+ * - interacts with various native libnsl configuration files
+ * - expects to register with a native rpcbind using /dev/ticlts
+ * Thus, this code is derived from the native lockd, but modified to address
+ * these issues and run inside an lx-branded zone. Because the Linux lockd
+ * lives entirely in the kernel, our lockd must be started automatically if
+ * it is needed. This is done by the NFS mount code when it determines that
+ * a lockd is not already running. The kernel code ensures that there is only a
+ * single instance of the lockd running, in the case that there is a race with
+ * two NFS mounts occuring in parallel.
+ *
+ * lockd is required for both NFSv3 and v4 locking. Although v4 locking is
+ * part of the v4 protocol, the kernel support to allow NFS locking is enabled
+ * by the lockd when it starts. For v3, there must be a lockd registered with
+ * rpcbind or the server side will fail the lock. This is because the server
+ * side expects to make callbacks to the client. We must successfully register
+ * with the Linux rpcbind, otherwise the NFS syscall to enable the kernel side
+ * of locking will fail. For the v3 case, the user-level Linux mount helper cmd
+ * already checks for the presence of rpcbind. It fails if rpcbind is not
+ * running and the mount does not include the "nolock" option. For v4 the use
+ * of rpcbind appears unnecessary, since locking is built-in to the protocol,
+ * but it still required by our kernel NFS locking code.
+ *
+ * As with the native lockd, the kernel locking code makes upcalls to our lockd
+ * over /dev/ticotsord, so that device must be present inside an lx zone.
+ *
+ * Because this process tries to mimic the Linux kernel lockd, there is no
+ * stdin/out/err and we block all signals, unless we're running in debug mode.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <tiuser.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <thread.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <nfs/nfs.h>
+#include <nfs/nfssys.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <string.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <sys/tihdr.h>
+#include <poll.h>
+#include <priv_utils.h>
+#include <sys/tiuser.h>
+#include <netinet/tcp.h>
+#include <deflt.h>
+#include <rpcsvc/nlm_prot.h>
+#include <ctype.h>
+#include <strings.h>
+#include <sys/varargs.h>
+#include <rpcsvc/nlm_prot.h>
+#include <rpc/pmap_prot.h>
+#include "nfs_tbind.h"
+#include "thrpool.h"
+
+/* Option defaults. See nfssys.h */
+struct lm_svc_args lmargs = {
+ .version = LM_SVC_CUR_VERS,
+ /* fd, n_fmly, n_proto, n_rdev (below) */
+ .n_v4_only = 0,
+ .timout = 5 * 60,
+ .grace = 90, /* How long to wait for clients to re-establish locks. */
+ .retransmittimeout = 5
+};
+int max_servers = 256;
+
+#define RET_OK 0 /* return code for no error */
+#define RET_ERR 33 /* return code for error(s) */
+
+#define SYSLOG_BLEN 256
+
+int nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf);
+
+static int nlmsvcpool(int max_servers);
+static void usage(void);
+
+static struct timeval tottimeout = { 60, 0 };
+static struct timeval rpcbtime = { 15, 0 };
+static const char nullstring[] = "\000";
+
+boolean_t have_rpcbind = B_FALSE;
+
+extern int _nfssys(int, void *);
+extern void nlm_do_one(char *, int (*)(int, struct netbuf, struct netconfig *));
+extern int nlm_bind_to_provider(char *, struct netbuf **, struct netconfig **);
+
+/*
+ * We want to bind to these TLI providers, and in this order,
+ * because the kernel NLM needs the loopback first for its
+ * initialization. (It uses it to talk to statd.)
+ */
+static NETSELDECL(defaultproviders)[] = {
+ "/dev/ticotsord",
+ "/dev/tcp",
+ "/dev/udp",
+ "/dev/tcp6",
+ "/dev/udp6",
+ NULL
+};
+
+/*
+ * The following are all globals used by routines in nfs_tbind.c.
+ */
+size_t end_listen_fds; /* used by conn_close_oldest() */
+size_t num_fds = 0; /* used by multiple routines */
+int listen_backlog = 32; /* used by bind_to_{provider,proto}() */
+ /* used by cots_listen_event() */
+int max_conns_allowed = -1; /* used by cots_listen_event() */
+int (*Mysvc)(int, struct netbuf, struct netconfig *) = nlmsvc;
+
+boolean_t debug = B_FALSE;
+
+#define LX_PMAP_VERS 4
+
+/*
+ * Set a mapping between program, version and address.
+ * Calls the lx-zone's rpcbind service to do the mapping.
+ */
+boolean_t
+lx_rpcb_set(const rpcvers_t version, const struct netconfig *nconf,
+ const struct netbuf *address)
+{
+ CLIENT *client;
+ bool_t rslt = FALSE;
+ RPCB parms;
+ char uidbuf[32];
+
+ client = clnt_create_timed("localhost", PMAPPROG, LX_PMAP_VERS,
+ "datagram_v", &rpcbtime);
+ if (client == NULL)
+ return (B_FALSE);
+
+ parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
+ (struct netbuf *)address); /* convert to universal */
+ if (!parms.r_addr) {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (B_FALSE);
+ }
+ parms.r_prog = NLM_PROG;
+ parms.r_vers = version;
+ parms.r_netid = nconf->nc_netid;
+ /*
+ * Though uid is not being used directly, we still send it for
+ * completeness. For non-unix platforms, perhaps some other
+ * string or an empty string can be sent.
+ */
+ (void) sprintf(uidbuf, "%d", (int)geteuid());
+ parms.r_owner = uidbuf;
+
+ CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
+ (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
+
+ CLNT_DESTROY(client);
+ free(parms.r_addr);
+ return (B_TRUE);
+}
+
+/*
+ * Remove the mapping between program, version and netbuf address.
+ * Calls the rpcbind service to do the un-mapping.
+ */
+void
+lx_rpcb_unset(const rpcvers_t version, char *nc_netid)
+{
+ CLIENT *client;
+ bool_t rslt;
+ RPCB parms;
+ char uidbuf[32];
+
+ if (!have_rpcbind)
+ return;
+
+ client = clnt_create_timed("localhost", PMAPPROG, LX_PMAP_VERS,
+ "datagram_v", &rpcbtime);
+ if (client == NULL)
+ return;
+
+ parms.r_prog = NLM_PROG;
+ parms.r_vers = version;
+ parms.r_netid = nc_netid;
+ parms.r_addr = (char *)&nullstring[0];
+ (void) sprintf(uidbuf, "%d", (int)geteuid());
+ parms.r_owner = uidbuf;
+
+ CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
+ (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
+
+ CLNT_DESTROY(client);
+}
+
+static void
+lx_nlm_unreg(char *provider)
+{
+ struct netconfig *retnconf;
+ int vers;
+
+ if (nlm_bind_to_provider(provider, NULL, &retnconf) == -1)
+ return;
+
+ /* Unregister all versions of the program. */
+ for (vers = NLM_VERS; vers <= NLM4_VERS; vers++) {
+ lx_rpcb_unset(vers, retnconf->nc_netid);
+ }
+}
+
+void
+lx_syslog(char *fmt, ...)
+{
+ int fd, l;
+ struct sockaddr_un snd_addr;
+ char buf[SYSLOG_BLEN], fb[SYSLOG_BLEN], *bp, *fp, *ep;
+ va_list ap;
+
+ /* First we replace %m in fmt string with error string into fb. */
+ ep = fb + sizeof (fb);
+ fb[SYSLOG_BLEN - 1] = '\0';
+ for (bp = fb, fp = fmt; bp < ep && (*bp = *fp) != '\0'; bp++, fp++) {
+ if (*fp == '%' && *(fp + 1) == 'm') {
+ (void) strlcpy(bp, strerror(errno), ep - bp);
+ bp += strlen(bp);
+ fp += 2;
+ }
+ }
+
+ va_start(ap, fmt);
+ (void) snprintf(buf, sizeof (buf), " rpc.lockd[%d]: ", getpid());
+ l = strlen(buf);
+ bp = &buf[l];
+ (void) vsnprintf(bp, sizeof (buf) - l, fb, ap);
+ va_end(ap);
+
+ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
+ return;
+
+ bzero(&snd_addr, sizeof (snd_addr));
+ strcpy(snd_addr.sun_path, "/dev/log");
+ snd_addr.sun_family = AF_LOCAL;
+ l = strlen(snd_addr.sun_path) + sizeof (snd_addr.sun_family);
+
+ if (connect(fd, (struct sockaddr *)&snd_addr, l) == 0) {
+ l = strlen(buf);
+ (void) send(fd, buf, l, 0);
+ }
+
+ close(fd);
+}
+
+/* When debugging, ensure cleanup */
+static void
+sigint_handler(void)
+{
+ NETSELPDECL(providerp);
+
+ lx_syslog("Stopping");
+
+ /* unregister from rpcbind */
+ for (providerp = defaultproviders; *providerp != NULL; providerp++) {
+ char *provider = *providerp;
+ lx_nlm_unreg(provider);
+ }
+ (void) _nfssys(KILL_LOCKMGR, NULL);
+
+ exit(0);
+}
+
+int
+main(int ac, char *av[])
+{
+ NETSELPDECL(providerp);
+ int i, c, val;
+
+ if (geteuid() != 0) {
+ exit(1);
+ }
+
+ /* Initializations that require more privileges than we need to run. */
+ if (__init_daemon_priv(PU_RESETGROUPS | PU_CLEARLIMITSET, 1, 1,
+ PRIV_SYS_NFS, NULL) == -1) {
+ exit(1);
+ }
+
+ (void) enable_extended_FILE_stdio(-1, -1);
+
+ while ((c = getopt(ac, av, "c:dg:l:t:")) != EOF)
+ switch (c) {
+ case 'c': /* max_connections */
+ if ((val = atoi(optarg)) <= 0)
+ goto badval;
+ max_conns_allowed = val;
+ break;
+
+ case 'd': /* debug */
+ debug = B_TRUE;
+ break;
+
+ case 'g': /* grace_period */
+ if ((val = atoi(optarg)) <= 0)
+ goto badval;
+ lmargs.grace = val;
+ break;
+
+ case 'l': /* listen_backlog */
+ if ((val = atoi(optarg)) <= 0)
+ goto badval;
+ listen_backlog = val;
+ break;
+
+ case 't': /* retrans_timeout */
+ if ((val = atoi(optarg)) <= 0)
+ goto badval;
+ lmargs.retransmittimeout = val;
+ break;
+
+ badval:
+ if (debug) {
+ fprintf(stderr, "Invalid -%c option value", c);
+ }
+ /* FALLTHROUGH */
+ default:
+ if (debug) {
+ usage();
+ }
+ exit(1);
+ }
+
+ /* If there is one more argument, it is the number of servers. */
+ if (optind < ac) {
+ val = atoi(av[optind]);
+ if (val <= 0) {
+ if (debug) {
+ fprintf(stderr, "Invalid max_servers argument");
+ usage();
+ }
+ exit(1);
+ }
+ max_servers = val;
+ optind++;
+ }
+ /* If there are two or more arguments, then this is a usage error. */
+ if (optind != ac) {
+ if (debug) {
+ usage();
+ }
+ exit(1);
+ }
+
+ if (debug) {
+ printf("lx_lockd: debug=%d, conn_idle_timout=%d, "
+ "grace_period=%d, listen_backlog=%d, "
+ "max_connections=%d, max_servers=%d, "
+ "retrans_timeout=%d\n",
+ debug, lmargs.timout, lmargs.grace, listen_backlog,
+ max_conns_allowed, max_servers, lmargs.retransmittimeout);
+ }
+
+ /* Set current dir to server root */
+ if (chdir("/") < 0) {
+ lx_syslog("chdir: %m");
+ exit(1);
+ }
+
+ if (!debug) {
+ /* Block all signals if not debugging. */
+ sigset_t set;
+
+ (void) sigfillset(&set);
+ (void) sigprocmask(SIG_BLOCK, &set, NULL);
+ (void) setsid();
+ } else {
+ struct sigaction act;
+
+ act.sa_handler = sigint_handler;
+ act.sa_flags = 0;
+ (void) sigaction(SIGINT, &act, NULL);
+ }
+
+ lx_syslog("Starting");
+
+ /* Unregister any previous versions. */
+ for (i = NLM_VERS; i < NLM4_VERS; i++) {
+ svc_unreg(NLM_PROG, i);
+ }
+
+ /* Set up kernel RPC thread pool for the NLM server. */
+ if (nlmsvcpool(max_servers)) {
+ lx_syslog("Can't set up kernel NLM service: %m. Exiting");
+ exit(1);
+ }
+
+ /* Set up blocked thread to do LWP creation on behalf of the kernel. */
+ if (svcwait(NLM_SVCPOOL_ID)) {
+ lx_syslog("Can't set up NLM pool creator: %m. Exiting");
+ exit(1);
+ }
+
+ for (providerp = defaultproviders; *providerp != NULL; providerp++) {
+ char *provider = *providerp;
+ nlm_do_one(provider, nlmsvc);
+ }
+
+ if (num_fds == 0) {
+ lx_syslog("Could not start NLM service for any protocol. "
+ "Exiting");
+ exit(1);
+ }
+
+ end_listen_fds = num_fds;
+
+ /*
+ * lockd is up and running as far as we are concerned.
+ *
+ * Get rid of unneeded privileges.
+ */
+ __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
+ PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
+
+ /* Poll for non-data control events on the transport descriptors. */
+ poll_for_action();
+
+ /* If we get here, something failed in poll_for_action(). */
+ return (1);
+}
+
+static int
+nlmsvcpool(int maxservers)
+{
+ struct svcpool_args npa;
+
+ npa.id = NLM_SVCPOOL_ID;
+ npa.maxthreads = maxservers;
+ npa.redline = 0;
+ npa.qsize = 0;
+ npa.timeout = 0;
+ npa.stksize = 0;
+ npa.max_same_xprt = 0;
+ return (_nfssys(SVCPOOL_CREATE, &npa));
+}
+
+static int
+ncfmly_to_lmfmly(const char *ncfmly)
+{
+ if (0 == strcmp(ncfmly, NC_INET))
+ return (LM_INET);
+ if (0 == strcmp(ncfmly, NC_INET6))
+ return (LM_INET6);
+ if (0 == strcmp(ncfmly, NC_LOOPBACK))
+ return (LM_LOOPBACK);
+ return (-1);
+}
+
+static int
+nctype_to_lmprot(uint_t semantics)
+{
+ switch (semantics) {
+ case NC_TPI_CLTS:
+ return (LM_UDP);
+ case NC_TPI_COTS_ORD:
+ return (LM_TCP);
+ }
+ return (-1);
+}
+
+static dev_t
+ncdev_to_rdev(const char *ncdev)
+{
+ struct stat st;
+
+ if (stat(ncdev, &st) < 0)
+ return (NODEV);
+ return (st.st_rdev);
+}
+
+/*
+ * Establish NLM service thread.
+ */
+int
+nlmsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
+{
+ struct lm_svc_args lma;
+
+ lma = lmargs; /* init by struct copy */
+
+ /*
+ * The kernel code needs to reconstruct a complete
+ * knetconfig from n_fmly, n_proto. We use these
+ * two fields to convey the family and semantics.
+ */
+ lma.fd = fd;
+ lma.n_fmly = ncfmly_to_lmfmly(nconf->nc_protofmly);
+ lma.n_proto = nctype_to_lmprot(nconf->nc_semantics);
+ lma.n_rdev = ncdev_to_rdev(nconf->nc_device);
+
+ if (!have_rpcbind) {
+ /*
+ * Inform the kernel NLM code to run without rpcbind and
+ * rpc.statd.
+ */
+ lma.n_v4_only = -1;
+ }
+
+ return (_nfssys(LM_SVC, &lma));
+}
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "usage: lx_lockd [options] [max_servers]\n");
+ (void) fprintf(stderr, "\t-c max_connections\n");
+ (void) fprintf(stderr, "\t-d enable debugging\n");
+ (void) fprintf(stderr, "\t-g grace_period\n");
+ (void) fprintf(stderr, "\t-l listen_backlog\n");
+ (void) fprintf(stderr, "\t-t retransmit_timeout\n");
+}
diff --git a/usr/src/lib/brand/lx/lx_lockd/nfs_tbind.c b/usr/src/lib/brand/lx/lx_lockd/nfs_tbind.c
new file mode 100644
index 0000000000..1f8f50e23c
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_lockd/nfs_tbind.c
@@ -0,0 +1,1832 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2014 Gary Mills
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * Derived from usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c, but modified to work
+ * within an lx-branded zone and to only support the lx lockd. Changes from the
+ * original have been minimized, thus this file is not cstyle or lint clean.
+ */
+
+#include <tiuser.h>
+#include <fcntl.h>
+#include <netconfig.h>
+#include <stropts.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <netdir.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/tcp.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include "nfs_tbind.h"
+#include <nfs/nfs.h>
+#include <nfs/nfs_acl.h>
+#include <nfs/nfssys.h>
+#include <nfs/nfs4.h>
+#include <zone.h>
+#include <sys/socket.h>
+#include <tsol/label.h>
+#include <sys/varargs.h>
+#include <rpcsvc/nlm_prot.h>
+
+/*
+ * Determine valid semantics for most applications.
+ */
+#define OK_TPI_TYPE(_nconf) \
+ (_nconf->nc_semantics == NC_TPI_CLTS || \
+ _nconf->nc_semantics == NC_TPI_COTS || \
+ _nconf->nc_semantics == NC_TPI_COTS_ORD)
+
+#define BE32_TO_U32(a) \
+ ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
+ (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
+ (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \
+ ((ulong_t)((uchar_t *)a)[3] & 0xFF))
+
+/*
+ * Number of elements to add to the poll array on each allocation.
+ */
+#define POLL_ARRAY_INC_SIZE 64
+
+/*
+ * Number of file descriptors by which the process soft limit may be
+ * increased on each call to nofile_increase(0).
+ */
+#define NOFILE_INC_SIZE 64
+
+/*
+ * Default TCP send and receive buffer size of NFS server.
+ */
+#define NFSD_TCP_BUFSZ (1024*1024)
+
+struct conn_ind {
+ struct conn_ind *conn_next;
+ struct conn_ind *conn_prev;
+ struct t_call *conn_call;
+};
+
+struct conn_entry {
+ bool_t closing;
+ struct netconfig nc;
+};
+
+/*
+ * this file contains transport routines common to nfsd and lockd
+ */
+static int nofile_increase(int);
+static int reuseaddr(int);
+static int recvucred(int);
+static int anonmlp(int);
+static void add_to_poll_list(int, struct netconfig *);
+static char *serv_name_to_port_name(char *);
+static int bind_to_proto(char *, char *, struct netbuf **,
+ struct netconfig **);
+int nlm_bind_to_provider(char *, struct netbuf **, struct netconfig **);
+static void conn_close_oldest(void);
+static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
+static void cots_listen_event(int, int);
+static int discon_get(int, struct netconfig *, struct conn_ind **);
+static int do_poll_clts_action(int, int);
+static int do_poll_cots_action(int, int);
+static void remove_from_poll_list(int);
+static int set_addrmask(int, struct netconfig *, struct netbuf *);
+static int is_listen_fd_index(int);
+
+static struct pollfd *poll_array;
+static struct conn_entry *conn_polled;
+static int num_conns; /* Current number of connections */
+int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
+ struct netbuf *);
+static int setopt(int fd, int level, int name, int value);
+static int get_opt(int fd, int level, int name);
+static void nfslib_set_sockbuf(int fd);
+
+extern boolean_t have_rpcbind;
+extern void lx_syslog(char *, ...);
+extern boolean_t lx_rpcb_set(const rpcvers_t, const struct netconfig *,
+ const struct netbuf *);
+extern void lx_rpcb_unset(const rpcvers_t, char *);
+
+/* We can't include syslog.h since we override it, so define these here. */
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_DEBUG 7
+
+/*
+ * Built-in netconfig table.
+ */
+#define N_NETCONF_ENTS 5
+static struct netconfig nca[N_NETCONF_ENTS] = {
+ {"udp6", NC_TPI_CLTS, 1, "inet6", "udp", "/dev/udp6", 0, NULL},
+ {"tcp6", NC_TPI_COTS_ORD, 1, "inet6", "tcp", "/dev/tcp6", 0, NULL},
+ {"udp", NC_TPI_CLTS, 1, "inet", "udp", "/dev/udp", 0, NULL},
+ {"tcp", NC_TPI_COTS_ORD, 1, "inet", "tcp", "/dev/tcp", 0, NULL},
+ {"ticotsord", NC_TPI_COTS_ORD, 1, "loopback", "-", "/dev/ticotsord", 0,
+ NULL}
+};
+
+/* To minimize file diffs we provide our own syslog wrapper. */
+static void
+syslog(int level, char *fmt, ...)
+{
+ va_list ap;
+
+ if (level == LOG_DEBUG)
+ return;
+ va_start(ap, fmt);
+ lx_syslog(fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Called to create and prepare a transport descriptor for in-kernel
+ * RPC service.
+ * Returns -1 on failure and a valid descriptor on success.
+ */
+int
+nfslib_transport_open(struct netconfig *nconf)
+{
+ int fd;
+ struct strioctl strioc;
+
+ if ((nconf == (struct netconfig *)NULL) ||
+ (nconf->nc_device == (char *)NULL)) {
+ syslog(LOG_ERR, "no netconfig device");
+ return (-1);
+ }
+
+ /*
+ * Open the transport device.
+ */
+ fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
+ if (fd == -1) {
+ if (t_errno == TSYSERR && errno == EMFILE &&
+ (nofile_increase(0) == 0)) {
+ /* Try again with a higher NOFILE limit. */
+ fd = t_open(nconf->nc_device, O_RDWR,
+ (struct t_info *)NULL);
+ }
+ if (fd == -1) {
+ syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m",
+ nconf->nc_device, t_errno);
+ return (-1);
+ }
+ }
+
+ /*
+ * Pop timod because the RPC module must be as close as possible
+ * to the transport.
+ */
+ if (ioctl(fd, I_POP, 0) < 0) {
+ syslog(LOG_ERR, "I_POP of timod failed: %m");
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ /*
+ * Common code for CLTS and COTS transports
+ */
+ if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
+ syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ strioc.ic_cmd = RPC_SERVER;
+ strioc.ic_dp = (char *)0;
+ strioc.ic_len = 0;
+ strioc.ic_timout = -1;
+
+ /* Tell rpcmod to act like a server stream. */
+ if (ioctl(fd, I_STR, &strioc) < 0) {
+ syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ /*
+ * Re-push timod so that we will still be doing TLI
+ * operations on the descriptor.
+ */
+ if (ioctl(fd, I_PUSH, "timod") < 0) {
+ syslog(LOG_ERR, "I_PUSH of timod failed: %m");
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ /*
+ * Enable options of returning the ip's for udp.
+ */
+ if (strcmp(nconf->nc_netid, "udp6") == 0)
+ __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1);
+ else if (strcmp(nconf->nc_netid, "udp") == 0)
+ __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1);
+
+ return (fd);
+}
+
+static int
+nofile_increase(int limit)
+{
+ struct rlimit rl;
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
+ return (-1);
+ }
+
+ if (limit > 0)
+ rl.rlim_cur = limit;
+ else
+ rl.rlim_cur += NOFILE_INC_SIZE;
+
+ if (rl.rlim_cur > rl.rlim_max &&
+ rl.rlim_max != RLIM_INFINITY)
+ rl.rlim_max = rl.rlim_cur;
+
+ if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
+ syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
+ rl.rlim_cur);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+nfslib_set_sockbuf(int fd)
+{
+ int curval, val;
+
+ val = NFSD_TCP_BUFSZ;
+
+ curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF);
+ syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval);
+ if ((curval != -1) && (curval < val)) {
+ syslog(LOG_DEBUG, "Set SO_SNDBUF option to %d", val);
+ if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) {
+ syslog(LOG_ERR,
+ "couldn't set SO_SNDBUF to %d - t_errno = %d",
+ val, t_errno);
+ syslog(LOG_ERR,
+ "Check and increase system-wide tcp_max_buf");
+ }
+ }
+
+ curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF);
+ syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval);
+ if ((curval != -1) && (curval < val)) {
+ syslog(LOG_DEBUG, "Set SO_RCVBUF option to %d", val);
+ if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) {
+ syslog(LOG_ERR,
+ "couldn't set SO_RCVBUF to %d - t_errno = %d",
+ val, t_errno);
+ syslog(LOG_ERR,
+ "Check and increase system-wide tcp_max_buf");
+ }
+ }
+}
+
+static int
+nlm_bindit(struct netconfig *nconf, struct netbuf **addr, int backlog)
+{
+ int fd;
+ struct t_bind *ntb;
+ struct t_bind tb;
+ struct nd_addrlist *addrlist;
+ struct t_optmgmt req, resp;
+ struct opthdr *opt;
+ char reqbuf[128];
+ struct nd_hostserv hs;
+
+ if ((fd = nfslib_transport_open(nconf)) == -1) {
+ syslog(LOG_ERR, "cannot establish transport service over %s",
+ nconf->nc_device);
+ return (-1);
+ }
+
+ addrlist = (struct nd_addrlist *)NULL;
+
+ /*
+ * This is the well-defined 'lockd' port from /etc/services. We can
+ * pass down the NLM port number to nlm_bindit and that resolves
+ * properly in the native *getby* calling paths.
+ */
+ hs.h_serv = "4045";
+ hs.h_host = HOST_SELF;
+
+ /*
+ * The following block is based on _netdir_getbyname in
+ * usr/src/lib/nametoaddr/straddr/common/straddr.c. This is what would
+ * be used by __classic_netdir_getbyname for the loopback.
+ */
+ if (strcmp(nconf->nc_netid, "ticotsord") == 0) {
+ struct nd_addrlist *ap;
+ struct netbuf *netbufp;
+ char *fulladdr = "localhost.4045";
+
+ if ((ap = malloc(sizeof (struct nd_addrlist))) == NULL) {
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ ap->n_cnt = 1;
+ if ((ap->n_addrs = malloc(sizeof (struct netbuf))) == NULL) {
+ free(ap);
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ netbufp = ap->n_addrs;
+
+ /* Don't include the terminating NULL character in the length */
+ netbufp->len = netbufp->maxlen = (int)strlen(fulladdr);
+ if ((netbufp->buf = strdup(fulladdr)) == NULL) {
+ free(netbufp);
+ free(ap);
+ (void) t_close(fd);
+ return (-1);
+ }
+ addrlist = ap;
+
+ } else if (netdir_getbyname(nconf, &hs, &addrlist) != 0) {
+ syslog(LOG_ERR,
+ "Cannot get address for transport %s",
+ nconf->nc_netid);
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ if (strcmp(nconf->nc_proto, "tcp") == 0) {
+ /*
+ * If we're running over TCP, then set the
+ * SO_REUSEADDR option so that we can bind
+ * to our preferred address even if previously
+ * left connections exist in FIN_WAIT states.
+ * This is somewhat bogus, but otherwise you have
+ * to wait 2 minutes to restart after killing it.
+ */
+ if (reuseaddr(fd) == -1) {
+ syslog(LOG_WARNING,
+ "couldn't set SO_REUSEADDR option on transport");
+ }
+ } else if (strcmp(nconf->nc_proto, "udp") == 0) {
+ /*
+ * In order to run MLP on UDP, we need to handle creds.
+ */
+ if (recvucred(fd) == -1) {
+ syslog(LOG_WARNING,
+ "couldn't set SO_RECVUCRED option on transport");
+ }
+ }
+
+ if (nconf->nc_semantics == NC_TPI_CLTS)
+ tb.qlen = 0;
+ else
+ tb.qlen = backlog;
+
+ /* LINTED pointer alignment */
+ ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
+ if (ntb == (struct t_bind *)NULL) {
+ syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno);
+ (void) t_close(fd);
+ netdir_free((void *)addrlist, ND_ADDRLIST);
+ return (-1);
+ }
+
+ /*
+ * XXX - what about the space tb->addr.buf points to? This should
+ * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
+ * should't be called with T_ALL.
+ */
+ if (addrlist)
+ tb.addr = *(addrlist->n_addrs); /* structure copy */
+
+ if (t_bind(fd, &tb, ntb) == -1) {
+ syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno);
+ (void) t_free((char *)ntb, T_BIND);
+ netdir_free((void *)addrlist, ND_ADDRLIST);
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ /* make sure we bound to the right address */
+ if (tb.addr.len != ntb->addr.len ||
+ memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0) {
+ syslog(LOG_ERR, "t_bind to wrong address");
+ (void) t_free((char *)ntb, T_BIND);
+ netdir_free((void *)addrlist, ND_ADDRLIST);
+ (void) t_close(fd);
+ return (-1);
+ }
+
+ *addr = &ntb->addr;
+ netdir_free((void *)addrlist, ND_ADDRLIST);
+
+ if (strcmp(nconf->nc_proto, "tcp") == 0) {
+ /*
+ * Disable the Nagle algorithm on TCP connections.
+ * Connections accepted from this listener will
+ * inherit the listener options.
+ */
+
+ /* LINTED pointer alignment */
+ opt = (struct opthdr *)reqbuf;
+ opt->level = IPPROTO_TCP;
+ opt->name = TCP_NODELAY;
+ opt->len = sizeof (int);
+
+ /* LINTED pointer alignment */
+ *(int *)((char *)opt + sizeof (*opt)) = 1;
+
+ req.flags = T_NEGOTIATE;
+ req.opt.len = sizeof (*opt) + opt->len;
+ req.opt.buf = (char *)opt;
+ resp.flags = 0;
+ resp.opt.buf = reqbuf;
+ resp.opt.maxlen = sizeof (reqbuf);
+
+ if (t_optmgmt(fd, &req, &resp) < 0 ||
+ resp.flags != T_SUCCESS) {
+ syslog(LOG_ERR,
+ "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
+ nconf->nc_proto, t_errno);
+ }
+
+ nfslib_set_sockbuf(fd);
+ }
+
+ return (fd);
+}
+
+static int
+get_opt(int fd, int level, int name)
+{
+ struct t_optmgmt req, res;
+ struct {
+ struct opthdr opt;
+ int value;
+ } reqbuf;
+
+ reqbuf.opt.level = level;
+ reqbuf.opt.name = name;
+ reqbuf.opt.len = sizeof (int);
+ reqbuf.value = 0;
+
+ req.flags = T_CURRENT;
+ req.opt.len = sizeof (reqbuf);
+ req.opt.buf = (char *)&reqbuf;
+
+ res.flags = 0;
+ res.opt.buf = (char *)&reqbuf;
+ res.opt.maxlen = sizeof (reqbuf);
+
+ if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
+ t_error("t_optmgmt");
+ return (-1);
+ }
+ return (reqbuf.value);
+}
+
+static int
+setopt(int fd, int level, int name, int value)
+{
+ struct t_optmgmt req, resp;
+ struct {
+ struct opthdr opt;
+ int value;
+ } reqbuf;
+
+ reqbuf.opt.level = level;
+ reqbuf.opt.name = name;
+ reqbuf.opt.len = sizeof (int);
+
+ reqbuf.value = value;
+
+ req.flags = T_NEGOTIATE;
+ req.opt.len = sizeof (reqbuf);
+ req.opt.buf = (char *)&reqbuf;
+
+ resp.flags = 0;
+ resp.opt.buf = (char *)&reqbuf;
+ resp.opt.maxlen = sizeof (reqbuf);
+
+ if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
+ t_error("t_optmgmt");
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+reuseaddr(int fd)
+{
+ return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
+}
+
+static int
+recvucred(int fd)
+{
+ return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
+}
+
+static int
+anonmlp(int fd)
+{
+ return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
+}
+
+void
+nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
+{
+ int error;
+
+ /*
+ * Save the error code across syslog(), just in case syslog()
+ * gets its own error and, therefore, overwrites errno.
+ */
+ error = errno;
+ if (t_errno == TSYSERR) {
+ syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
+ tli_name, fd, nconf->nc_proto);
+ } else {
+ syslog(LOG_ERR,
+ "%s(file descriptor %d/transport %s) TLI error %d",
+ tli_name, fd, nconf->nc_proto, t_errno);
+ }
+ errno = error;
+}
+
+/*
+ * Called to set up service over a particular transport.
+ */
+void
+nlm_do_one(char *provider, int (*svc)(int, struct netbuf, struct netconfig *))
+{
+ register int sock;
+ struct netbuf *retaddr;
+ struct netconfig *retnconf;
+ struct netbuf addrmask;
+ int vers;
+ int err;
+ static boolean_t elogged = B_FALSE;
+
+ sock = nlm_bind_to_provider(provider, &retaddr, &retnconf);
+ if (sock == -1) {
+ (void) syslog(LOG_ERR,
+ "Cannot establish NLM service over %s: transport setup problem.",
+ provider);
+ return;
+ }
+
+ if (set_addrmask(sock, retnconf, &addrmask) < 0) {
+ (void) syslog(LOG_ERR,
+ "Cannot set address mask for %s", retnconf->nc_netid);
+ return;
+ }
+
+ /* Register all versions of the NLM with rpcbind. */
+ if (strcmp(provider, "/dev/ticotsord") != 0) {
+ for (vers = NLM_VERS; vers <= NLM4_VERS; vers++) {
+ lx_rpcb_unset(vers, retnconf->nc_netid);
+ have_rpcbind = lx_rpcb_set(vers, retnconf, retaddr);
+ if (!have_rpcbind && !elogged) {
+ /*
+ * No rpcbind running. The kernel NFS locking
+ * code interacts with rpcbind & rpc.statd for
+ * NFSv3 locking. We warn about this but
+ * proceed since NFSv4 locking is still usable.
+ */
+ lx_syslog("Warning: rpcbind is not running, "
+ "but is required for NFSv3 locking");
+ elogged = B_TRUE;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Register services with CLTS semantics right now.
+ * Note: services with COTS/COTS_ORD semantics will be
+ * registered later from cots_listen_event function.
+ */
+ if (retnconf->nc_semantics == NC_TPI_CLTS) {
+ /* Don't drop core if supporting module(s) aren't loaded. */
+ (void) signal(SIGSYS, SIG_IGN);
+
+ /*
+ * svc() doesn't block, it returns success or failure.
+ */
+
+ if (svc == NULL && Mysvc4 != NULL)
+ err = (*Mysvc4)(sock, &addrmask, retnconf,
+ NFS4_SETPORT|NFS4_KRPC_START, retaddr);
+ else
+ err = (*svc)(sock, addrmask, retnconf);
+
+ if (err < 0) {
+ (void) syslog(LOG_ERR,
+ "Cannot establish NLM service over <file desc."
+ " %d, protocol %s> : %m. Exiting",
+ sock, retnconf->nc_proto);
+ exit(1);
+ }
+ }
+ free(addrmask.buf);
+
+ /*
+ * We successfully set up the server over this transport.
+ * Add this descriptor to the one being polled on.
+ */
+ add_to_poll_list(sock, retnconf);
+}
+
+/*
+ * Set up the NFS service over all the available transports.
+ * Returns -1 for failure, 0 for success.
+ */
+int
+do_all(struct protob *protobp,
+ int (*svc)(int, struct netbuf, struct netconfig *))
+{
+ struct netconfig *nconf;
+ NCONF_HANDLE *nc;
+ int l;
+
+ if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
+ syslog(LOG_ERR, "setnetconfig failed: %m");
+ return (-1);
+ }
+ l = strlen(NC_UDP);
+ while (nconf = getnetconfig(nc)) {
+ if ((nconf->nc_flag & NC_VISIBLE) &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
+ OK_TPI_TYPE(nconf) &&
+ (protobp->program != NFS4_CALLBACK ||
+ strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
+ continue; /* do_all should never be called */
+ }
+ (void) endnetconfig(nc);
+ return (0);
+}
+
+/*
+ * poll on the open transport descriptors for events and errors.
+ */
+void
+poll_for_action(void)
+{
+ int nfds;
+ int i;
+
+ /*
+ * Keep polling until all transports have been closed. When this
+ * happens, we return.
+ */
+ while ((int)num_fds > 0) {
+ nfds = poll(poll_array, num_fds, INFTIM);
+ switch (nfds) {
+ case 0:
+ continue;
+
+ case -1:
+ /*
+ * Some errors from poll could be
+ * due to temporary conditions, and we try to
+ * be robust in the face of them. Other
+ * errors (should never happen in theory)
+ * are fatal (eg. EINVAL, EFAULT).
+ */
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EAGAIN:
+ case ENOMEM:
+ (void) sleep(10);
+ continue;
+
+ default:
+ (void) syslog(LOG_ERR,
+ "poll failed: %m. Exiting");
+ exit(1);
+ }
+ default:
+ break;
+ }
+
+ /*
+ * Go through the poll list looking for events.
+ */
+ for (i = 0; i < num_fds && nfds > 0; i++) {
+ if (poll_array[i].revents) {
+ nfds--;
+ /*
+ * We have a message, so try to read it.
+ * Record the error return in errno,
+ * so that syslog(LOG_ERR, "...%m")
+ * dumps the corresponding error string.
+ */
+ if (conn_polled[i].nc.nc_semantics ==
+ NC_TPI_CLTS) {
+ errno = do_poll_clts_action(
+ poll_array[i].fd, i);
+ } else {
+ errno = do_poll_cots_action(
+ poll_array[i].fd, i);
+ }
+
+ if (errno == 0)
+ continue;
+ /*
+ * Most returned error codes mean that there is
+ * fatal condition which we can only deal with
+ * by closing the transport.
+ */
+ if (errno != EAGAIN && errno != ENOMEM) {
+ (void) syslog(LOG_ERR,
+ "Error (%m) reading descriptor %d/transport %s. Closing it.",
+ poll_array[i].fd,
+ conn_polled[i].nc.nc_proto);
+ (void) t_close(poll_array[i].fd);
+ remove_from_poll_list(poll_array[i].fd);
+
+ } else if (errno == ENOMEM)
+ (void) sleep(5);
+ }
+ }
+ }
+
+ (void) syslog(LOG_ERR,
+ "All transports have been closed with errors. Exiting.");
+}
+
+/*
+ * Allocate poll/transport array entries for this descriptor.
+ */
+static void
+add_to_poll_list(int fd, struct netconfig *nconf)
+{
+ static int poll_array_size = 0;
+
+ /*
+ * If the arrays are full, allocate new ones.
+ */
+ if (num_fds == poll_array_size) {
+ struct pollfd *tpa;
+ struct conn_entry *tnp;
+
+ if (poll_array_size != 0) {
+ tpa = poll_array;
+ tnp = conn_polled;
+ } else
+ tpa = (struct pollfd *)0;
+
+ poll_array_size += POLL_ARRAY_INC_SIZE;
+ /*
+ * Allocate new arrays.
+ */
+ poll_array = (struct pollfd *)
+ malloc(poll_array_size * sizeof (struct pollfd) + 256);
+ conn_polled = (struct conn_entry *)
+ malloc(poll_array_size * sizeof (struct conn_entry) + 256);
+ if (poll_array == (struct pollfd *)NULL ||
+ conn_polled == (struct conn_entry *)NULL) {
+ syslog(LOG_ERR, "malloc failed for poll array");
+ exit(1);
+ }
+
+ /*
+ * Copy the data of the old ones into new arrays, and
+ * free the old ones.
+ */
+ if (tpa) {
+ (void) memcpy((void *)poll_array, (void *)tpa,
+ num_fds * sizeof (struct pollfd));
+ (void) memcpy((void *)conn_polled, (void *)tnp,
+ num_fds * sizeof (struct conn_entry));
+ free((void *)tpa);
+ free((void *)tnp);
+ }
+ }
+
+ /*
+ * Set the descriptor and event list. All possible events are
+ * polled for.
+ */
+ poll_array[num_fds].fd = fd;
+ poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
+
+ /*
+ * Copy the transport data over too.
+ */
+ conn_polled[num_fds].nc = *nconf;
+ conn_polled[num_fds].closing = 0;
+
+ /*
+ * Set the descriptor to non-blocking. Avoids a race
+ * between data arriving on the stream and then having it
+ * flushed before we can read it.
+ */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ (void) syslog(LOG_ERR,
+ "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
+ num_fds, nconf->nc_proto);
+ exit(1);
+ }
+
+ /*
+ * Count this descriptor.
+ */
+ ++num_fds;
+}
+
+static void
+remove_from_poll_list(int fd)
+{
+ int i;
+ int num_to_copy;
+
+ for (i = 0; i < num_fds; i++) {
+ if (poll_array[i].fd == fd) {
+ --num_fds;
+ num_to_copy = num_fds - i;
+ (void) memcpy((void *)&poll_array[i],
+ (void *)&poll_array[i+1],
+ num_to_copy * sizeof (struct pollfd));
+ (void) memset((void *)&poll_array[num_fds], 0,
+ sizeof (struct pollfd));
+ (void) memcpy((void *)&conn_polled[i],
+ (void *)&conn_polled[i+1],
+ num_to_copy * sizeof (struct conn_entry));
+ (void) memset((void *)&conn_polled[num_fds], 0,
+ sizeof (struct conn_entry));
+ return;
+ }
+ }
+ syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
+
+}
+
+/*
+ * Called to read and interpret the event on a connectionless descriptor.
+ * Returns 0 if successful, or a UNIX error code if failure.
+ */
+static int
+do_poll_clts_action(int fd, int conn_index)
+{
+ int error;
+ int ret;
+ int flags;
+ struct netconfig *nconf = &conn_polled[conn_index].nc;
+ static struct t_unitdata *unitdata = NULL;
+ static struct t_uderr *uderr = NULL;
+ static int oldfd = -1;
+ struct nd_hostservlist *host = NULL;
+ struct strbuf ctl[1], data[1];
+ /*
+ * We just need to have some space to consume the
+ * message in the event we can't use the TLI interface to do the
+ * job.
+ *
+ * We flush the message using getmsg(). For the control part
+ * we allocate enough for any TPI header plus 32 bytes for address
+ * and options. For the data part, there is nothing magic about
+ * the size of the array, but 256 bytes is probably better than
+ * 1 byte, and we don't expect any data portion anyway.
+ *
+ * If the array sizes are too small, we handle this because getmsg()
+ * (called to consume the message) will return MOREDATA|MORECTL.
+ * Thus we just call getmsg() until it's read the message.
+ */
+ char ctlbuf[sizeof (union T_primitives) + 32];
+ char databuf[256];
+
+ /*
+ * If this is the same descriptor as the last time
+ * do_poll_clts_action was called, we can save some
+ * de-allocation and allocation.
+ */
+ if (oldfd != fd) {
+ oldfd = fd;
+
+ if (unitdata) {
+ (void) t_free((char *)unitdata, T_UNITDATA);
+ unitdata = NULL;
+ }
+ if (uderr) {
+ (void) t_free((char *)uderr, T_UDERROR);
+ uderr = NULL;
+ }
+ }
+
+ /*
+ * Allocate a unitdata structure for receiving the event.
+ */
+ if (unitdata == NULL) {
+ /* LINTED pointer alignment */
+ unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
+ if (unitdata == NULL) {
+ if (t_errno == TSYSERR) {
+ /*
+ * Save the error code across
+ * syslog(), just in case
+ * syslog() gets its own error
+ * and therefore overwrites errno.
+ */
+ error = errno;
+ (void) syslog(LOG_ERR,
+ "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
+ fd, nconf->nc_proto);
+ return (error);
+ }
+ (void) syslog(LOG_ERR,
+"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
+ fd, nconf->nc_proto, t_errno);
+ goto flush_it;
+ }
+ }
+
+try_again:
+ flags = 0;
+
+ /*
+ * The idea is we wait for T_UNITDATA_IND's. Of course,
+ * we don't get any, because rpcmod filters them out.
+ * However, we need to call t_rcvudata() to let TLI
+ * tell us we have a T_UDERROR_IND.
+ *
+ * algorithm is:
+ * t_rcvudata(), expecting TLOOK.
+ * t_look(), expecting T_UDERR.
+ * t_rcvuderr(), expecting success (0).
+ * expand destination address into ASCII,
+ * and dump it.
+ */
+
+ ret = t_rcvudata(fd, unitdata, &flags);
+ if (ret == 0 || t_errno == TBUFOVFLW) {
+ (void) syslog(LOG_WARNING,
+"t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
+ fd, nconf->nc_proto, unitdata->udata.len);
+
+ /*
+ * Even though we don't expect any data, in case we do,
+ * keep reading until there is no more.
+ */
+ if (flags & T_MORE)
+ goto try_again;
+
+ return (0);
+ }
+
+ switch (t_errno) {
+ case TNODATA:
+ return (0);
+ case TSYSERR:
+ /*
+ * System errors are returned to caller.
+ * Save the error code across
+ * syslog(), just in case
+ * syslog() gets its own error
+ * and therefore overwrites errno.
+ */
+ error = errno;
+ (void) syslog(LOG_ERR,
+ "t_rcvudata(file descriptor %d/transport %s) %m",
+ fd, nconf->nc_proto);
+ return (error);
+ case TLOOK:
+ break;
+ default:
+ (void) syslog(LOG_ERR,
+ "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
+ fd, nconf->nc_proto, t_errno);
+ goto flush_it;
+ }
+
+ ret = t_look(fd);
+ switch (ret) {
+ case 0:
+ return (0);
+ case -1:
+ /*
+ * System errors are returned to caller.
+ */
+ if (t_errno == TSYSERR) {
+ /*
+ * Save the error code across
+ * syslog(), just in case
+ * syslog() gets its own error
+ * and therefore overwrites errno.
+ */
+ error = errno;
+ (void) syslog(LOG_ERR,
+ "t_look(file descriptor %d/transport %s) %m",
+ fd, nconf->nc_proto);
+ return (error);
+ }
+ (void) syslog(LOG_ERR,
+ "t_look(file descriptor %d/transport %s) TLI error %d",
+ fd, nconf->nc_proto, t_errno);
+ goto flush_it;
+ case T_UDERR:
+ break;
+ default:
+ (void) syslog(LOG_WARNING,
+ "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
+ fd, nconf->nc_proto, ret, T_UDERR);
+ }
+
+ if (uderr == NULL) {
+ /* LINTED pointer alignment */
+ uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
+ if (uderr == NULL) {
+ if (t_errno == TSYSERR) {
+ /*
+ * Save the error code across
+ * syslog(), just in case
+ * syslog() gets its own error
+ * and therefore overwrites errno.
+ */
+ error = errno;
+ (void) syslog(LOG_ERR,
+ "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
+ fd, nconf->nc_proto);
+ return (error);
+ }
+ (void) syslog(LOG_ERR,
+"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
+ fd, nconf->nc_proto, t_errno);
+ goto flush_it;
+ }
+ }
+
+ ret = t_rcvuderr(fd, uderr);
+ if (ret == 0) {
+
+ /*
+ * Save the datagram error in errno, so that the
+ * %m argument to syslog picks up the error string.
+ */
+ errno = uderr->error;
+
+ /*
+ * Log the datagram error, then log the host that
+ * probably triggerred. Cannot log both in the
+ * same transaction because of packet size limitations
+ * in /dev/log.
+ */
+ (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
+"NFS response over <file descriptor %d/transport %s> generated error: %m",
+ fd, nconf->nc_proto);
+
+ /*
+ * Try to map the client's address back to a
+ * name.
+ */
+ ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
+ if (ret != -1 && host && host->h_cnt > 0 &&
+ host->h_hostservs) {
+ (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
+"Bad NFS response was sent to client with host name: %s; service port: %s",
+ host->h_hostservs->h_host,
+ host->h_hostservs->h_serv);
+ } else {
+ int i, j;
+ char *buf;
+ char *hex = "0123456789abcdef";
+
+ /*
+ * Mapping failed, print the whole thing
+ * in ASCII hex.
+ */
+ buf = (char *)malloc(uderr->addr.len * 2 + 1);
+ for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
+ buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
+ buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
+ }
+ buf[j] = '\0';
+ (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
+ "Bad NFS response was sent to client with transport address: 0x%s",
+ buf);
+ free((void *)buf);
+ }
+
+ if (ret == 0 && host != NULL)
+ netdir_free((void *)host, ND_HOSTSERVLIST);
+ return (0);
+ }
+
+ switch (t_errno) {
+ case TNOUDERR:
+ goto flush_it;
+ case TSYSERR:
+ /*
+ * System errors are returned to caller.
+ * Save the error code across
+ * syslog(), just in case
+ * syslog() gets its own error
+ * and therefore overwrites errno.
+ */
+ error = errno;
+ (void) syslog(LOG_ERR,
+ "t_rcvuderr(file descriptor %d/transport %s) %m",
+ fd, nconf->nc_proto);
+ return (error);
+ default:
+ (void) syslog(LOG_ERR,
+ "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
+ fd, nconf->nc_proto, t_errno);
+ goto flush_it;
+ }
+
+flush_it:
+ /*
+ * If we get here, then we could not cope with whatever message
+ * we attempted to read, so flush it. If we did read a message,
+ * and one isn't present, that is all right, because fd is in
+ * nonblocking mode.
+ */
+ (void) syslog(LOG_ERR,
+ "Flushing one input message from <file descriptor %d/transport %s>",
+ fd, nconf->nc_proto);
+
+ /*
+ * Read and discard the message. Do this this until there is
+ * no more control/data in the message or until we get an error.
+ */
+ do {
+ ctl->maxlen = sizeof (ctlbuf);
+ ctl->buf = ctlbuf;
+ data->maxlen = sizeof (databuf);
+ data->buf = databuf;
+ flags = 0;
+ ret = getmsg(fd, ctl, data, &flags);
+ if (ret == -1)
+ return (errno);
+ } while (ret != 0);
+
+ return (0);
+}
+
+static void
+conn_close_oldest(void)
+{
+ int fd;
+ int i1;
+
+ /*
+ * Find the oldest connection that is not already in the
+ * process of shutting down.
+ */
+ for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
+ if (i1 >= num_fds)
+ return;
+ if (conn_polled[i1].closing == 0)
+ break;
+ }
+#ifdef DEBUG
+ printf("too many connections (%d), releasing oldest (%d)\n",
+ num_conns, poll_array[i1].fd);
+#else
+ syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
+ num_conns, poll_array[i1].fd);
+#endif
+ fd = poll_array[i1].fd;
+ if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
+ /*
+ * For politeness, send a T_DISCON_REQ to the transport
+ * provider. We close the stream anyway.
+ */
+ (void) t_snddis(fd, (struct t_call *)0);
+ num_conns--;
+ remove_from_poll_list(fd);
+ (void) t_close(fd);
+ } else {
+ /*
+ * For orderly release, we do not close the stream
+ * until the T_ORDREL_IND arrives to complete
+ * the handshake.
+ */
+ if (t_sndrel(fd) == 0)
+ conn_polled[i1].closing = 1;
+ }
+}
+
+static boolean_t
+conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
+{
+ struct conn_ind *conn;
+ struct conn_ind *next_conn;
+
+ conn = (struct conn_ind *)malloc(sizeof (*conn));
+ if (conn == NULL) {
+ syslog(LOG_ERR, "malloc for listen indication failed");
+ return (FALSE);
+ }
+
+ /* LINTED pointer alignment */
+ conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
+ if (conn->conn_call == NULL) {
+ free((char *)conn);
+ nfslib_log_tli_error("t_alloc", fd, nconf);
+ return (FALSE);
+ }
+
+ if (t_listen(fd, conn->conn_call) == -1) {
+ nfslib_log_tli_error("t_listen", fd, nconf);
+ (void) t_free((char *)conn->conn_call, T_CALL);
+ free((char *)conn);
+ return (FALSE);
+ }
+
+ if (conn->conn_call->udata.len > 0) {
+ syslog(LOG_WARNING,
+ "rejecting inbound connection(%s) with %d bytes of connect data",
+ nconf->nc_proto, conn->conn_call->udata.len);
+
+ conn->conn_call->udata.len = 0;
+ (void) t_snddis(fd, conn->conn_call);
+ (void) t_free((char *)conn->conn_call, T_CALL);
+ free((char *)conn);
+ return (FALSE);
+ }
+
+ if ((next_conn = *connp) != NULL) {
+ next_conn->conn_prev->conn_next = conn;
+ conn->conn_next = next_conn;
+ conn->conn_prev = next_conn->conn_prev;
+ next_conn->conn_prev = conn;
+ } else {
+ conn->conn_next = conn;
+ conn->conn_prev = conn;
+ *connp = conn;
+ }
+ return (TRUE);
+}
+
+static int
+discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
+{
+ struct conn_ind *conn;
+ struct t_discon discon;
+
+ discon.udata.buf = (char *)0;
+ discon.udata.maxlen = 0;
+ if (t_rcvdis(fd, &discon) == -1) {
+ nfslib_log_tli_error("t_rcvdis", fd, nconf);
+ return (-1);
+ }
+
+ conn = *connp;
+ if (conn == NULL)
+ return (0);
+
+ do {
+ if (conn->conn_call->sequence == discon.sequence) {
+ if (conn->conn_next == conn)
+ *connp = (struct conn_ind *)0;
+ else {
+ if (conn == *connp) {
+ *connp = conn->conn_next;
+ }
+ conn->conn_next->conn_prev = conn->conn_prev;
+ conn->conn_prev->conn_next = conn->conn_next;
+ }
+ free((char *)conn);
+ break;
+ }
+ conn = conn->conn_next;
+ } while (conn != *connp);
+
+ return (0);
+}
+
+static void
+cots_listen_event(int fd, int conn_index)
+{
+ struct t_call *call;
+ struct conn_ind *conn;
+ struct conn_ind *conn_head;
+ int event;
+ struct netconfig *nconf = &conn_polled[conn_index].nc;
+ int new_fd;
+ struct netbuf addrmask;
+ int ret = 0;
+ char *clnt;
+ char *clnt_uaddr = NULL;
+ struct nd_hostservlist *clnt_serv = NULL;
+
+ conn_head = NULL;
+ (void) conn_get(fd, nconf, &conn_head);
+
+ while ((conn = conn_head) != NULL) {
+ conn_head = conn->conn_next;
+ if (conn_head == conn)
+ conn_head = NULL;
+ else {
+ conn_head->conn_prev = conn->conn_prev;
+ conn->conn_prev->conn_next = conn_head;
+ }
+ call = conn->conn_call;
+ free(conn);
+
+ /*
+ * If we have already accepted the maximum number of
+ * connections allowed on the command line, then drop
+ * the oldest connection (for any protocol) before
+ * accepting the new connection. Unless explicitly
+ * set on the command line, max_conns_allowed is -1.
+ */
+ if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
+ conn_close_oldest();
+
+ /*
+ * Create a new transport endpoint for the same proto as
+ * the listener.
+ */
+ new_fd = nfslib_transport_open(nconf);
+ if (new_fd == -1) {
+ call->udata.len = 0;
+ (void) t_snddis(fd, call);
+ (void) t_free((char *)call, T_CALL);
+ syslog(LOG_ERR, "Cannot establish transport over %s",
+ nconf->nc_device);
+ continue;
+ }
+
+ /* Bind to a generic address/port for the accepting stream. */
+ if (t_bind(new_fd, NULL, NULL) == -1) {
+ nfslib_log_tli_error("t_bind", new_fd, nconf);
+ call->udata.len = 0;
+ (void) t_snddis(fd, call);
+ (void) t_free((char *)call, T_CALL);
+ (void) t_close(new_fd);
+ continue;
+ }
+
+ while (t_accept(fd, new_fd, call) == -1) {
+ if (t_errno != TLOOK) {
+#ifdef DEBUG
+ nfslib_log_tli_error("t_accept", fd, nconf);
+#endif
+ call->udata.len = 0;
+ (void) t_snddis(fd, call);
+ (void) t_free((char *)call, T_CALL);
+ (void) t_close(new_fd);
+ goto do_next_conn;
+ }
+ while (event = t_look(fd)) {
+ switch (event) {
+ case T_LISTEN:
+#ifdef DEBUG
+ printf(
+"cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
+#endif
+ (void) conn_get(fd, nconf, &conn_head);
+ continue;
+ case T_DISCONNECT:
+#ifdef DEBUG
+ printf(
+ "cots_listen_event(%s): T_DISCONNECT during accept processing\n",
+ nconf->nc_proto);
+#endif
+ (void) discon_get(fd, nconf,
+ &conn_head);
+ continue;
+ default:
+ syslog(LOG_ERR,
+ "unexpected event 0x%x during accept processing (%s)",
+ event, nconf->nc_proto);
+ call->udata.len = 0;
+ (void) t_snddis(fd, call);
+ (void) t_free((char *)call, T_CALL);
+ (void) t_close(new_fd);
+ goto do_next_conn;
+ }
+ }
+ }
+
+ if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
+ (void) syslog(LOG_ERR,
+ "Cannot set address mask for %s",
+ nconf->nc_netid);
+ (void) t_snddis(new_fd, NULL);
+ (void) t_free((char *)call, T_CALL);
+ (void) t_close(new_fd);
+ continue;
+ }
+
+ /* Tell kRPC about the new stream. */
+ if (Mysvc4 != NULL)
+ ret = (*Mysvc4)(new_fd, &addrmask, nconf,
+ NFS4_KRPC_START, &call->addr);
+ else
+ ret = (*Mysvc)(new_fd, addrmask, nconf);
+
+ if (ret < 0) {
+ if (errno != ENOTCONN) {
+ syslog(LOG_ERR,
+ "unable to register new connection: %m");
+ } else {
+ /*
+ * This is the only error that could be
+ * caused by the client, so who was it?
+ */
+ if (netdir_getbyaddr(nconf, &clnt_serv,
+ &(call->addr)) == ND_OK &&
+ clnt_serv->h_cnt > 0)
+ clnt = clnt_serv->h_hostservs->h_host;
+ else
+ clnt = clnt_uaddr = taddr2uaddr(nconf,
+ &(call->addr));
+ /*
+ * If we don't know who the client was,
+ * remain silent.
+ */
+ if (clnt)
+ syslog(LOG_ERR,
+"unable to register new connection: client %s has dropped connection", clnt);
+ if (clnt_serv) {
+ netdir_free(clnt_serv, ND_HOSTSERVLIST);
+ clnt_serv = NULL;
+ }
+ if (clnt_uaddr) {
+ free(clnt_uaddr);
+ clnt_uaddr = NULL;
+ }
+ }
+ free(addrmask.buf);
+ (void) t_snddis(new_fd, NULL);
+ (void) t_free((char *)call, T_CALL);
+ (void) t_close(new_fd);
+ goto do_next_conn;
+ }
+
+ free(addrmask.buf);
+ (void) t_free((char *)call, T_CALL);
+
+ /*
+ * Poll on the new descriptor so that we get disconnect
+ * and orderly release indications.
+ */
+ num_conns++;
+ add_to_poll_list(new_fd, nconf);
+
+ /* Reset nconf in case it has been moved. */
+ nconf = &conn_polled[conn_index].nc;
+do_next_conn:;
+ }
+}
+
+static int
+do_poll_cots_action(int fd, int conn_index)
+{
+ char buf[256];
+ int event;
+ int i1;
+ int flags;
+ struct conn_entry *connent = &conn_polled[conn_index];
+ struct netconfig *nconf = &(connent->nc);
+ const char *errorstr;
+
+ while (event = t_look(fd)) {
+ switch (event) {
+ case T_LISTEN:
+#ifdef DEBUG
+printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
+#endif
+ cots_listen_event(fd, conn_index);
+ break;
+
+ case T_DATA:
+#ifdef DEBUG
+printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
+#endif
+ /*
+ * Receive a private notification from CONS rpcmod.
+ */
+ i1 = t_rcv(fd, buf, sizeof (buf), &flags);
+ if (i1 == -1) {
+ syslog(LOG_ERR, "t_rcv failed");
+ break;
+ }
+ if (i1 < sizeof (int))
+ break;
+ i1 = BE32_TO_U32(buf);
+ if (i1 == 1 || i1 == 2) {
+ /*
+ * This connection has been idle for too long,
+ * so release it as politely as we can. If we
+ * have already initiated an orderly release
+ * and we get notified that the stream is
+ * still idle, pull the plug. This prevents
+ * hung connections from continuing to consume
+ * resources.
+ */
+#ifdef DEBUG
+printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
+printf("initiating orderly release of idle connection\n");
+#endif
+ if (nconf->nc_semantics == NC_TPI_COTS ||
+ connent->closing != 0) {
+ (void) t_snddis(fd, (struct t_call *)0);
+ goto fdclose;
+ }
+ /*
+ * For NC_TPI_COTS_ORD, the stream is closed
+ * and removed from the poll list when the
+ * T_ORDREL is received from the provider. We
+ * don't wait for it here because it may take
+ * a while for the transport to shut down.
+ */
+ if (t_sndrel(fd) == -1) {
+ syslog(LOG_ERR,
+ "unable to send orderly release %m");
+ }
+ connent->closing = 1;
+ } else
+ syslog(LOG_ERR,
+ "unexpected event from CONS rpcmod %d", i1);
+ break;
+
+ case T_ORDREL:
+#ifdef DEBUG
+printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
+#endif
+ /* Perform an orderly release. */
+ if (t_rcvrel(fd) == 0) {
+ /* T_ORDREL on listen fd's should be ignored */
+ if (!is_listen_fd_index(conn_index)) {
+ (void) t_sndrel(fd);
+ goto fdclose;
+ }
+ break;
+
+ } else if (t_errno == TLOOK) {
+ break;
+ } else {
+ nfslib_log_tli_error("t_rcvrel", fd, nconf);
+
+ /*
+ * check to make sure we do not close
+ * listen fd
+ */
+ if (is_listen_fd_index(conn_index))
+ break;
+ else
+ goto fdclose;
+ }
+
+ case T_DISCONNECT:
+#ifdef DEBUG
+printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
+#endif
+ if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
+ nfslib_log_tli_error("t_rcvdis", fd, nconf);
+
+ /*
+ * T_DISCONNECT on listen fd's should be ignored.
+ */
+ if (is_listen_fd_index(conn_index))
+ break;
+ else
+ goto fdclose;
+
+ default:
+ if (t_errno == TSYSERR) {
+ if ((errorstr = strerror(errno)) == NULL) {
+ (void) sprintf(buf,
+ "Unknown error num %d", errno);
+ errorstr = (const char *) buf;
+ }
+ } else if (event == -1)
+ errorstr = t_strerror(t_errno);
+ else
+ errorstr = "";
+ syslog(LOG_ERR,
+ "unexpected TLI event (0x%x) on "
+ "connection-oriented transport(%s,%d):%s",
+ event, nconf->nc_proto, fd, errorstr);
+fdclose:
+ num_conns--;
+ remove_from_poll_list(fd);
+ (void) t_close(fd);
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+static char *
+serv_name_to_port_name(char *name)
+{
+ /*
+ * Map service names (used primarily in logging) to
+ * RPC port names (used by netdir_*() routines).
+ */
+ if (strcmp(name, "NFS") == 0) {
+ return ("nfs");
+ } else if (strcmp(name, "NLM") == 0) {
+ return ("lockd");
+ } else if (strcmp(name, "NFS4_CALLBACK") == 0) {
+ return ("nfs4_callback");
+ }
+
+ return ("unrecognized");
+}
+
+int
+nlm_bind_to_provider(char *provider, struct netbuf **addr,
+ struct netconfig **retnconf)
+{
+ int i, res;
+ struct netconfig *nconf = NULL, *np;
+
+ for (i = 0; i < N_NETCONF_ENTS; i++) {
+ np = &nca[i];
+
+ if (strcmp(np->nc_device, provider) != 0)
+ continue;
+
+ /* Construct our own netconfig */
+ if ((nconf = calloc(1, sizeof (struct netconfig))) == NULL)
+ goto out;
+
+ nconf->nc_semantics = np->nc_semantics;
+ if ((nconf->nc_netid = strdup(np->nc_netid)) == NULL)
+ goto out;
+ if ((nconf->nc_protofmly = strdup(np->nc_protofmly)) == NULL)
+ goto out;
+ if ((nconf->nc_proto = strdup(np->nc_proto)) == NULL)
+ goto out;
+ if ((nconf->nc_device = strdup(np->nc_device)) == NULL)
+ goto out;
+
+ *retnconf = nconf;
+
+ /*
+ * Passing addr == NULL implies we skip the bind since we only
+ * need the netconfig for unregistering from rpcbind.
+ */
+ if (addr == NULL)
+ return (0);
+ if ((res = nlm_bindit(nconf, addr, listen_backlog)) == -1)
+ freenetconfigent(nconf);
+ return (res);
+ }
+
+out:
+ if (nconf != NULL)
+ freenetconfigent(nconf);
+ syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
+ provider);
+ return (-1);
+}
+
+static int
+bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
+ struct netconfig **retnconf)
+{
+ struct netconfig *nconf;
+ NCONF_HANDLE *nc = NULL;
+ struct nd_hostserv hs;
+
+ hs.h_host = HOST_SELF;
+ hs.h_serv = serv_name_to_port_name(serv);
+
+ if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
+ syslog(LOG_ERR, "setnetconfig failed: %m");
+ return (-1);
+ }
+ while (nconf = getnetconfig(nc)) {
+ if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
+ *retnconf = nconf;
+ return (nfslib_bindit(nconf, addr, &hs,
+ listen_backlog));
+ }
+ }
+ (void) endnetconfig(nc);
+
+ syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
+ proto);
+ return (-1);
+}
+
+#include <netinet/in.h>
+
+/*
+ * Create an address mask appropriate for the transport.
+ * The mask is used to obtain the host-specific part of
+ * a network address when comparing addresses.
+ * For an internet address the host-specific part is just
+ * the 32 bit IP address and this part of the mask is set
+ * to all-ones. The port number part of the mask is zeroes.
+ */
+static int
+set_addrmask(int fd, struct netconfig *nconf, struct netbuf *mask)
+{
+ struct t_info info;
+
+ /*
+ * Find the size of the address we need to mask.
+ */
+ if (t_getinfo(fd, &info) < 0) {
+ t_error("t_getinfo");
+ return (-1);
+ }
+ mask->len = mask->maxlen = info.addr;
+ if (info.addr <= 0) {
+ /*
+ * loopback devices have infinite addr size
+ * (it is identified by -1 in addr field of t_info structure),
+ * so don't build the netmask for them. It's a special case
+ * that should be handled properly.
+ */
+ if ((info.addr == -1) &&
+ (0 == strcmp(nconf->nc_protofmly, NC_LOOPBACK))) {
+ memset(mask, 0, sizeof (*mask));
+ return (0);
+ }
+
+ syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr);
+ return (-1);
+ }
+
+ mask->buf = (char *)malloc(mask->len);
+ if (mask->buf == NULL) {
+ syslog(LOG_ERR, "set_addrmask: no memory");
+ return (-1);
+ }
+ (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */
+
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ /*
+ * Set the mask so that the port is ignored.
+ */
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
+ (ulong_t)~0;
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in *)mask->buf)->sin_family =
+ (ushort_t)~0;
+ } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
+ /* LINTED pointer alignment */
+ (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
+ (uchar_t)~0, sizeof (struct in6_addr));
+ /* LINTED pointer alignment */
+ ((struct sockaddr_in6 *)mask->buf)->sin6_family =
+ (ushort_t)~0;
+ } else {
+
+ /*
+ * Set all mask bits.
+ */
+ (void) memset(mask->buf, 0xFF, mask->len);
+ }
+ return (0);
+}
+
+/*
+ * For listen fd's index is always less than end_listen_fds.
+ * end_listen_fds is defined externally in the daemon that uses this library.
+ * It's value is equal to the number of open file descriptors after the
+ * last listen end point was opened but before any connection was accepted.
+ */
+static int
+is_listen_fd_index(int index)
+{
+ return (index < end_listen_fds);
+}
diff --git a/usr/src/lib/brand/lx/lx_support/Makefile b/usr/src/lib/brand/lx/lx_support/Makefile
new file mode 100644
index 0000000000..e7c958e13a
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_support/Makefile
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG = lx_support
+PROGS = $(PROG)
+OBJS = lx_support
+
+all: $(PROG)
+
+include ../Makefile.lx
+include $(SRC)/cmd/Makefile.cmd
+
+# override the install directory
+ROOTBIN = $(ROOTBRANDDIR)
+CLOBBERFILES = $(OBJS) $(ROOTPROGS)
+
+UTSBASE = $(SRC)/uts
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -D_REENTRANT -I$(UTSBASE)/common/brand/lx
+LDLIBS += -lzonecfg
+
+.KEEP_STATE:
+
+install: all $(ROOTPROGS)
+
+clean:
+ $(RM) $(PROG) $(OBJS)
+
+lint: lint_PROG
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/lib/brand/lx/lx_support/lx_support.c b/usr/src/lib/brand/lx/lx_support/lx_support.c
new file mode 100644
index 0000000000..d35c68ed8d
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_support/lx_support.c
@@ -0,0 +1,392 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * lx_support is a small cli utility used to perform some brand-specific
+ * tasks when booting, halting, or verifying a zone. This utility is not
+ * intended to be called by users - it is intended to be invoked by the
+ * zones utilities.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stropts.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <locale.h>
+
+#include <libzonecfg.h>
+#include <sys/lx_brand.h>
+
+static void lxs_err(char *msg, ...) __NORETURN;
+static void usage(void) __NORETURN;
+
+#define CP_CMD "/usr/bin/cp"
+#define MOUNT_CMD "/sbin/mount"
+
+static char *bname = NULL;
+static char *zonename = NULL;
+static char *zoneroot = NULL;
+
+#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
+#endif
+
+static void
+lxs_err(char *msg, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, msg);
+ /*LINTED*/
+ (void) vsnprintf(buf, sizeof (buf), msg, ap);
+ va_end(ap);
+
+ (void) printf("%s error: %s\n", bname, buf);
+
+ exit(1);
+ /*NOTREACHED*/
+}
+
+/*
+ * Cleanup from earlier versions of the code which created a /dev/initctl FIFO.
+ */
+static void
+lxs_remove_initctl()
+{
+ char special[MAXPATHLEN];
+
+ if (snprintf(special, sizeof (special), "%s/dev/initctl", zoneroot) >=
+ sizeof (special))
+ lxs_err("%s: %s", gettext("Failed to cleanup /dev/initctl"),
+ gettext("zoneroot is too long"));
+
+ (void) unlink(special);
+}
+
+/*
+ * fsck gets really confused when run inside a zone. Removing this file
+ * prevents it from running
+ */
+static void
+lxs_remove_autofsck()
+{
+ char path[MAXPATHLEN];
+ int err;
+
+ if (snprintf(path, MAXPATHLEN, "%s/root/.autofsck", zoneroot) >=
+ MAXPATHLEN)
+ lxs_err("%s: %s", gettext("Failed to remove /.autofsck"),
+ gettext("zoneroot is too long"));
+
+ if (unlink(path) < 0) {
+ err = errno;
+ if (err != ENOENT)
+ lxs_err("%s: %s",
+ gettext("Failed to remove /.autofsck"),
+ strerror(err));
+ }
+}
+
+/*
+ * Extract any lx-supported attributes from the zone configuration file.
+ */
+static void
+lxs_getattrs(zone_dochandle_t zdh, char **krelease)
+{
+ struct zone_attrtab attrtab;
+ int err;
+
+ /* initialize the attribute iterator */
+ if (zonecfg_setattrent(zdh) != Z_OK) {
+ zonecfg_fini_handle(zdh);
+ lxs_err(gettext("error accessing zone configuration"));
+ }
+
+ *krelease = (char *)malloc(LX_KERN_RELEASE_MAX);
+ if (*krelease == NULL)
+ lxs_err(gettext("out of memory"));
+
+ bzero(*krelease, LX_KERN_RELEASE_MAX);
+ while ((err = zonecfg_getattrent(zdh, &attrtab)) == Z_OK) {
+ if ((strcmp(attrtab.zone_attr_name, "kernel-version") == 0) &&
+ (zonecfg_get_attr_string(&attrtab, *krelease,
+ LX_KERN_RELEASE_MAX) != Z_OK))
+ lxs_err(gettext("invalid type for zone attribute: %s"),
+ attrtab.zone_attr_name);
+ }
+
+ if (strlen(*krelease) == 0) {
+ free(*krelease);
+ *krelease = NULL;
+ }
+
+ /* some kind of error while looking up attributes */
+ if (err != Z_NO_ENTRY)
+ lxs_err(gettext("error accessing zone configuration"));
+}
+
+/*
+ * Attempt to lookup the "tty" gid from within the zone's /etc/group file.
+ * The gid is used to emulate existing Linux udev behavior for setting the gid
+ * on a pty. If we cannot lookup the gid for some reason, we still allow
+ * the zone to boot.
+ *
+ * Because we're reading the lx zone's /etc/group file, we have to parse it
+ * ourselves, but this is simple since we only need the gid.
+ */
+static void
+lxs_set_ttygid(zoneid_t zoneid)
+{
+ char buf[MAXPATHLEN];
+ FILE *fp;
+ gid_t tty_gid = 0;
+
+ if (snprintf(buf, sizeof (buf), "%s/root/etc/group", zoneroot) >=
+ sizeof (buf))
+ return;
+
+ if ((fp = fopen(buf, "r")) == NULL)
+ return;
+
+ /*
+ * Look for the "tty" line and get the gid. Note that this loop will
+ * properly handle a long line that won't fit into buf on a single
+ * fgets. The subsequent fgets will consume more of the line but we
+ * continue on through that. In practice this is unlikely to occur.
+ */
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ char *p, *p_id;
+ long val;
+
+ /* group name */
+ if ((p = strchr(buf, ':')) == NULL)
+ continue;
+ *p = '\0';
+ if (strcmp(buf, "tty") != 0)
+ continue;
+
+ /* found tty entry, skip the "x" field */
+ if ((p = strchr(p + 1, ':')) == NULL)
+ goto done;
+ /* gid field */
+ p_id = p + 1;
+ if ((p = strchr(p_id, ':')) == NULL)
+ goto done;
+ *p = '\0';
+
+ errno = 0;
+ val = strtol(p_id, &p, 10);
+ /* Perform simple validation on the gid */
+ if (errno != 0 || *p != '\0' || val > MAXUID || val < 0)
+ goto done;
+ tty_gid = (gid_t)val;
+ break;
+ }
+
+ if (tty_gid != 0)
+ (void) zone_setattr(zoneid, LX_ATTR_TTY_GID, &tty_gid,
+ sizeof (tty_gid));
+
+done:
+ (void) fclose(fp);
+}
+
+static int
+lxs_boot()
+{
+ zoneid_t zoneid;
+ zone_dochandle_t zdh;
+ char *krelease;
+
+ lxs_remove_initctl();
+ lxs_remove_autofsck();
+
+ if ((zdh = zonecfg_init_handle()) == NULL)
+ lxs_err(gettext("unable to initialize zone handle"));
+
+ if (zonecfg_get_handle((char *)zonename, zdh) != Z_OK) {
+ zonecfg_fini_handle(zdh);
+ lxs_err(gettext("unable to load zone configuration"));
+ }
+
+ /* Extract any relevant attributes from the config file. */
+ lxs_getattrs(zdh, &krelease);
+ zonecfg_fini_handle(zdh);
+
+ /*
+ * Let the kernel know whether or not this zone's init process
+ * should be automatically restarted on its death.
+ */
+ if ((zoneid = getzoneidbyname(zonename)) < 0)
+ lxs_err(gettext("unable to get zoneid"));
+
+ if (krelease != NULL) {
+ /* Backward compatability with incomplete version attr */
+ if (strcmp(krelease, "2.4") == 0) {
+ krelease = "2.4.21";
+ } else if (strcmp(krelease, "2.6") == 0) {
+ krelease = "2.6.18";
+ }
+
+ if (zone_setattr(zoneid, LX_ATTR_KERN_RELEASE, krelease,
+ strlen(krelease)) < 0)
+ lxs_err(gettext("unable to set kernel version"));
+ }
+
+ lxs_set_ttygid(zoneid);
+
+ return (0);
+}
+
+static int
+lxs_halt()
+{
+ return (0);
+}
+
+static int
+lxs_verify(char *xmlfile)
+{
+ zone_dochandle_t handle;
+ char *krelease;
+ char hostidp[HW_HOSTID_LEN];
+ zone_iptype_t iptype;
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ lxs_err(gettext("internal libzonecfg.so.1 error"), 0);
+
+ if (zonecfg_get_xml_handle(xmlfile, handle) != Z_OK) {
+ zonecfg_fini_handle(handle);
+ lxs_err(gettext("zonecfg provided an invalid XML file"));
+ }
+
+ /*
+ * Check to see whether the zone has hostid emulation enabled.
+ */
+ if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK) {
+ zonecfg_fini_handle(handle);
+ lxs_err(gettext("lx zones do not support hostid emulation"));
+ }
+
+ /*
+ * Only exclusive stack is supported.
+ */
+ if (zonecfg_get_iptype(handle, &iptype) != Z_OK ||
+ iptype != ZS_EXCLUSIVE) {
+ zonecfg_fini_handle(handle);
+ lxs_err(gettext("lx zones do not support shared IP stacks"));
+ }
+
+ /* Extract any relevant attributes from the config file. */
+ lxs_getattrs(handle, &krelease);
+ zonecfg_fini_handle(handle);
+
+ if (krelease) {
+ char *pdot, *ep;
+ long major_ver;
+
+ pdot = strchr(krelease, '.');
+ if (pdot != NULL)
+ *pdot = '\0';
+ errno = 0;
+ major_ver = strtol(krelease, &ep, 10);
+ if (major_ver < 2 || errno != 0 || *ep != '\0')
+ lxs_err(gettext("invalid value for zone attribute: %s"),
+ "kernel-version");
+ if (pdot != NULL)
+ *pdot = '.';
+
+ }
+ return (0);
+}
+
+static void
+usage()
+{
+
+ (void) fprintf(stderr,
+ gettext("usage:\t%s boot <zoneroot> <zonename>\n"), bname);
+ (void) fprintf(stderr,
+ gettext(" \t%s halt <zoneroot> <zonename>\n"), bname);
+ (void) fprintf(stderr,
+ gettext(" \t%s verify <xml file>\n\n"), bname);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ bname = basename(argv[0]);
+
+ if (argc < 3)
+ usage();
+
+ if (strcmp(argv[1], "boot") == 0) {
+ if (argc != 4)
+ lxs_err(gettext("usage: %s %s <zoneroot> <zonename>"),
+ bname, argv[1]);
+ zoneroot = argv[2];
+ zonename = argv[3];
+ return (lxs_boot());
+ }
+
+ if (strcmp(argv[1], "halt") == 0) {
+ if (argc != 4)
+ lxs_err(gettext("usage: %s %s <zoneroot> <zonename>"),
+ bname, argv[1]);
+ zoneroot = argv[2];
+ zonename = argv[3];
+ return (lxs_halt());
+ }
+
+ if (strcmp(argv[1], "verify") == 0) {
+ if (argc != 3)
+ lxs_err(gettext("usage: %s verify <xml file>"),
+ bname);
+ return (lxs_verify(argv[2]));
+ }
+
+ usage();
+ /*NOTREACHED*/
+}
diff --git a/usr/src/lib/brand/lx/lx_vdso/Makefile b/usr/src/lib/brand/lx/lx_vdso/Makefile
new file mode 100644
index 0000000000..56dd0a7a3c
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/Makefile
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+include ../../../Makefile.lib
+
+SUBDIRS = tools $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber: $(SUBDIRS)
+
+lint: $(LINT_SUBDIRS)
+
+$(MACH): tools
+$(MACH64): tools
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/brand/lx/lx_vdso/Makefile.com b/usr/src/lib/brand/lx/lx_vdso/Makefile.com
new file mode 100644
index 0000000000..b6d46d38cd
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/Makefile.com
@@ -0,0 +1,85 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+LIBRARY = lx_vdso.a
+VERS = .1
+
+include $(SRC)/lib/commpage/Makefile.shared.com
+
+COBJS = vdso_main.o vdso_subr.o
+OBJECTS = $(COBJS) $(COMMPAGE_OBJS)
+
+include ../../../../Makefile.lib
+include ../../Makefile.lx
+
+#
+# Since our name doesn't start with "lib", Makefile.lib incorrectly
+# calculates LIBNAME. Therefore, we set it here.
+#
+LIBNAME = lx_vdso
+
+MAPFILES = ../common/mapfile-vers
+MAPOPTS = $(MAPFILES:%=-M%)
+
+ASOBJS = vdso_subr.o
+COBJS = vdso_main.o
+OBJECTS = $(ASOBJS) $(COBJS) $(COMMPAGE_OBJS)
+
+SRCDIR = ../common
+
+ASSRCS = $(ASOBJS:%.o=$(ISASRCDIR)/%.s)
+CSRCS = $(COBJS:%.o=$(SRCDIR)/%.c)
+SRCS = $(ASSRCS) $(CSRCS)
+
+LIBS = $(DYNLIB)
+DYNFLAGS += $(DYNFLAGS_$(CLASS))
+DYNFLAGS += $(MAPOPTS)
+LDLIBS +=
+ASFLAGS = -P $(ASFLAGS_$(CURTYPE)) -D_ASM
+
+
+LIBS = $(DYNLIB)
+
+CLEANFILES += $(DYNLIB)
+ROOTLIBDIR = $(ROOT)/usr/lib/brand/lx
+ROOTLIBDIR64 = $(ROOT)/usr/lib/brand/lx/$(MACH64)
+
+VDSO_TOOL = ../tools/vdso_tool
+
+.KEEP_STATE:
+
+#
+# While $(VDSO_TOOL) performs most of the transformations required to
+# construct a correct VDSO object, we still make use of $(ELFEDIT). To
+# remove the $(ELFEDIT) requirement would mean shouldering the burden of
+# becoming a link-editor; this dark lore is best left to the linker aliens.
+#
+all: $(LIBS)
+ $(ELFEDIT) -e "dyn:value -add VERSYM $$($(ELFEDIT) \
+ -e 'shdr:dump .SUNW_versym' $(DYNLIB) | \
+ $(AWK) '{ if ($$1 == "sh_addr:") { print $$2 } }')" $(DYNLIB)
+ $(VDSO_TOOL) -f $(DYNLIB)
+
+lint: $(LINTLIB) lintcheck
+
+include ../../../../Makefile.targ
+include $(SRC)/lib/commpage/Makefile.shared.targ
+
+pics/%.o: $(ISASRCDIR)/%.s
+ $(COMPILE.s) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/vdso_main.o := CPPFLAGS += $(COMMPAGE_CPPFLAGS) -I$(SRCDIR)
+pics/vdso_subr.o := ASFLAGS += -I$(SRC)/uts/common/brand/lx -I$(SRCDIR)
diff --git a/usr/src/lib/brand/lx/lx_vdso/amd64/Makefile b/usr/src/lib/brand/lx/lx_vdso/amd64/Makefile
new file mode 100644
index 0000000000..1a12492a97
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/amd64/Makefile
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+ISASRCDIR=.
+TARGET_ARCH=$(MACH64)
+
+include ../Makefile.com
+include $(SRC)/lib/Makefile.lib.64
+
+ASFLAGS += -D__$(MACH64)
+
+SONAME = linux-vdso.so.1
+
+# Disable save-args since some vDSO consumers are sensitive to stack usage.
+SAVEARGS =
+
+#
+# You might ask, why aren't we overriding BUILD.SO in Makefile.com.
+# That's a sad story. The answer is that Makefile.lib.64 includes
+# Makefile.master.64 which redefines BUILD.SO, leaving us in an
+# unfortunate jumble. Therefore we have to redefine it in the
+# lower-level Makefile.
+#
+BUILD.SO = $(LD) -o $@ $(GSHARED) $(DYNFLAGS) $(PICS) $(LDLIBS)
+
+ASSYMDEP_OBJS = lx_vdso.o
+
+CLOBBERFILES = $(ROOTLIBDIR64)/$(DYNLIB) $(ROOTLIBDIR64)/$(LINTLIB)
+
+install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/brand/lx/lx_vdso/amd64/vdso_subr.s b/usr/src/lib/brand/lx/lx_vdso/amd64/vdso_subr.s
new file mode 100644
index 0000000000..592884aa32
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/amd64/vdso_subr.s
@@ -0,0 +1,131 @@
+/*
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+
+#include <sys/asm_linkage.h>
+#include <sys/lx_syscalls.h>
+#include <vdso_defs.h>
+
+#if defined(lint)
+
+comm_page_t *
+__vdso_find_commpage()
+{}
+
+long
+__vdso_sys_clock_gettime(uint_t clock_id, timespec_t *tp)
+{}
+
+int
+__vdso_sys_gettimeofday(timespec_t *tp, struct lx_timezone *tz)
+{}
+
+time_t
+__vdso_sys_time(timespec_t *tp)
+{}
+
+#else /* lint */
+
+ ENTRY_NP(__vdso_find_commpage)
+ leaq 0x0(%rip), %rax
+ andq $LX_VDSO_ADDR_MASK, %rax
+ addq $LX_VDSO_SIZE, %rax
+ ret
+ SET_SIZE(__vdso_find_commpage)
+
+ ENTRY_NP(__vdso_sys_clock_gettime)
+ movl $LX_SYS_clock_gettime, %eax
+ syscall
+ ret
+ SET_SIZE(__vdso_sys_clock_gettime)
+
+ ENTRY_NP(__vdso_sys_gettimeofday)
+ movl $LX_SYS_gettimeofday, %eax
+ syscall
+ ret
+ SET_SIZE(__vdso_sys_gettimeofday)
+
+ ENTRY_NP(__vdso_sys_time)
+ movl $LX_SYS_time, %eax
+ syscall
+ ret
+ SET_SIZE(__vdso_sys_time)
+
+/*
+ * long
+ * __vdso_clock_gettime(uint_t, timespec_t *)
+ */
+ ENTRY_NP(__vdso_clock_gettime)
+ subq $0x18, %rsp
+ movl %edi, (%rsp)
+ movq %rsi, 0x8(%rsp)
+
+ call __vdso_find_commpage
+ movq %rax, 0x10(%rsp)
+
+ movq %rax, %rdi
+ call __cp_can_gettime
+ cmpl $0, %eax
+ je 5f
+
+ /*
+ * Restore the original args/stack (with commpage pointer in rdx)
+ * This enables the coming tail-call to the desired function, be it
+ * __cp_clock_gettime_* or __vdso_sys_clock_gettime.
+ */
+ movl (%rsp), %edi
+ movq 0x8(%rsp), %rsi
+ movq 0x10(%rsp), %rdx
+ addq $0x18, %rsp
+
+ cmpl $LX_CLOCK_REALTIME, %edi
+ jne 2f
+1:
+ movq %rdx, %rdi
+ jmp __cp_clock_gettime_realtime
+
+2:
+ cmpl $LX_CLOCK_MONOTONIC, %edi
+ jne 4f
+3:
+ movq %rdx, %rdi
+ jmp __cp_clock_gettime_monotonic
+
+4:
+ cmpl $LX_CLOCK_REALTIME_COARSE, %edi
+ je 1b
+ cmpl $LX_CLOCK_MONOTONIC_RAW, %edi
+ je 3b
+ cmpl $LX_CLOCK_MONOTONIC_COARSE, %edi
+ je 3b
+ jmp 6f
+
+5:
+ /*
+ * When falling through from a failed cp_can_gettime, the stack
+ * allocation must be released before a tail-call is made to the
+ * fallback syscall function.
+ */
+ addq $0x18, %rsp
+
+6:
+ /* Let the real syscall handle all other cases */
+ jmp __vdso_sys_clock_gettime
+ SET_SIZE(__vdso_clock_gettime)
+
+
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_vdso/common/mapfile-vers b/usr/src/lib/brand/lx/lx_vdso/common/mapfile-vers
new file mode 100644
index 0000000000..11690ce7d6
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/common/mapfile-vers
@@ -0,0 +1,59 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION LINUX_2.6 {
+ global:
+ __vdso_gettimeofday;
+ __vdso_clock_gettime;
+ __vdso_getcpu;
+ __vdso_time;
+ local:
+ *;
+};
+
+#
+# The vDSO module in GNU/Linux must only have a single PT_LOAD section.
+# Further, we should not have any data sections at all. Therefore, we go
+# through and explicitly disable several of the writeable sections that
+# might commonly show up.
+#
+LOAD_SEGMENT data {
+ disable;
+};
+
+LOAD_SEGMENT ldata {
+ disable;
+};
+
+LOAD_SEGMENT bss {
+ disable;
+};
+
diff --git a/usr/src/lib/brand/lx/lx_vdso/common/vdso_defs.h b/usr/src/lib/brand/lx/lx_vdso/common/vdso_defs.h
new file mode 100644
index 0000000000..dfac918a53
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/common/vdso_defs.h
@@ -0,0 +1,42 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#ifndef _VDSO_DEFS_H_
+#define _VDSO_DEFS_H_
+
+#define LX_CLOCK_REALTIME 0 /* CLOCK_REALTIME */
+#define LX_CLOCK_MONOTONIC 1 /* CLOCK_HIGHRES */
+#define LX_CLOCK_PROCESS_CPUTIME_ID 2 /* Emulated */
+#define LX_CLOCK_THREAD_CPUTIME_ID 3 /* Emulated */
+#define LX_CLOCK_MONOTONIC_RAW 4 /* CLOCK_HIGHRES */
+#define LX_CLOCK_REALTIME_COARSE 5 /* CLOCK_REALTIME */
+#define LX_CLOCK_MONOTONIC_COARSE 6 /* CLOCK_HIGHRES */
+
+#if !defined(_ASM)
+
+struct lx_timezone {
+ int tz_minuteswest; /* minutes W of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+/* Functions provided by the mach-specific vdso_subr.s */
+extern comm_page_t *__vdso_find_commpage();
+extern int __vdso_sys_gettimeofday(timespec_t *, struct lx_timezone *);
+extern time_t __vdso_sys_time(time_t *);
+extern long __vdso_sys_clock_gettime(uint_t, timespec_t *);
+
+#endif /* !defined(_ASM) */
+
+#endif /* _VDSO_DEFS_H_ */
diff --git a/usr/src/lib/brand/lx/lx_vdso/common/vdso_main.c b/usr/src/lib/brand/lx/lx_vdso/common/vdso_main.c
new file mode 100644
index 0000000000..f7d86e3da4
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/common/vdso_main.c
@@ -0,0 +1,139 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <cp_defs.h>
+#include <vdso_defs.h>
+
+
+#if defined(__i386)
+
+long
+__vdso_clock_gettime(uint_t clock_id, timespec_t *tp)
+{
+ comm_page_t *cp = __vdso_find_commpage();
+
+ if (__cp_can_gettime(cp) == 0) {
+ return (__vdso_sys_clock_gettime(clock_id, tp));
+ }
+
+ switch (clock_id) {
+ case LX_CLOCK_REALTIME:
+ case LX_CLOCK_REALTIME_COARSE:
+ return (__cp_clock_gettime_realtime(cp, tp));
+
+ case LX_CLOCK_MONOTONIC:
+ case LX_CLOCK_MONOTONIC_RAW:
+ case LX_CLOCK_MONOTONIC_COARSE:
+ return (__cp_clock_gettime_monotonic(cp, tp));
+
+ case LX_CLOCK_PROCESS_CPUTIME_ID:
+ case LX_CLOCK_THREAD_CPUTIME_ID:
+ default:
+ return (__vdso_sys_clock_gettime(clock_id, tp));
+ }
+}
+
+/*
+ * On i386, the implementation of __cp_clock_gettime_monotonic expects that an
+ * hrt2ts function is provided. It is provided below since the vDSO is
+ * operating on its own, without native libc.
+ */
+void
+hrt2ts(hrtime_t hrt, timespec_t *tsp)
+{
+ uint32_t sec, nsec, tmp;
+
+ tmp = (uint32_t)(hrt >> 30);
+ sec = tmp - (tmp >> 2);
+ sec = tmp - (sec >> 5);
+ sec = tmp + (sec >> 1);
+ sec = tmp - (sec >> 6) + 7;
+ sec = tmp - (sec >> 3);
+ sec = tmp + (sec >> 1);
+ sec = tmp + (sec >> 3);
+ sec = tmp + (sec >> 4);
+ tmp = (sec << 7) - sec - sec - sec;
+ tmp = (tmp << 7) - tmp - tmp - tmp;
+ tmp = (tmp << 7) - tmp - tmp - tmp;
+ nsec = (uint32_t)hrt - (tmp << 9);
+ while (nsec >= NANOSEC) {
+ nsec -= NANOSEC;
+ sec++;
+ }
+ tsp->tv_sec = (time_t)sec;
+ tsp->tv_nsec = nsec;
+}
+
+#else
+
+/*
+ * On amd64, the __vdso_clock_gettime function is implemented in asm to stay
+ * within the allowed stack budget.
+ */
+
+#endif /* defined(__i386) */
+
+
+int
+__vdso_gettimeofday(timespec_t *tp, struct lx_timezone *tz)
+{
+ if (tz != NULL) {
+ tz->tz_minuteswest = 0;
+ tz->tz_dsttime = 0;
+ }
+
+ if (tp != NULL) {
+ comm_page_t *cp = __vdso_find_commpage();
+
+ if (__cp_can_gettime(cp) == 0) {
+ return (__vdso_sys_gettimeofday(tp, tz));
+ }
+
+ __cp_clock_gettime_realtime(cp, tp);
+ tp->tv_nsec /= 1000;
+ }
+ return (0);
+}
+
+time_t
+__vdso_time(time_t *tp)
+{
+ comm_page_t *cp = __vdso_find_commpage();
+ timespec_t ts;
+
+ if (__cp_can_gettime(cp) == 0) {
+ return (__vdso_sys_time(tp));
+ }
+
+ __cp_clock_gettime_realtime(cp, &ts);
+ if (tp != NULL) {
+ *tp = ts.tv_sec;
+ }
+ return (ts.tv_sec);
+}
+
+int
+__vdso_getcpu(uint_t *cpu, uint_t *node, void *tcache)
+{
+ comm_page_t *cp = __vdso_find_commpage();
+
+ if (cpu != NULL) {
+ *cpu = __cp_getcpu(cp);
+ }
+ if (node != NULL) {
+ *node = 0;
+ }
+ return (0);
+}
diff --git a/usr/src/lib/brand/lx/lx_vdso/i386/Makefile b/usr/src/lib/brand/lx/lx_vdso/i386/Makefile
new file mode 100644
index 0000000000..7f9a6a13e6
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/i386/Makefile
@@ -0,0 +1,43 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+ISASRCDIR=.
+TARGET_ARCH=$(MACH)
+
+include ../Makefile.com
+
+ASFLAGS += -D__$(MACH)
+
+SONAME = linux-gate.so.1
+
+#
+# You might ask, why aren't we overriding BUILD.SO in Makefile.com.
+# See the amd64 Makefile for more answers
+#
+BUILD.SO = $(LD) -o $@ $(GSHARED) $(DYNFLAGS) $(PICS) $(LDLIBS)
+
+ASSYMDEP_OBJS = lx_vdso.o
+
+CLOBBERFILES = $(ROOTLIBDIR)/$(DYNLIB) $(ROOTLIBDIR)/$(LINTLIB)
+
+# Set the object entry point for __vsyscall-ers
+entryfix: $(DYNLIB)
+ $(ELFEDIT) -e "ehdr:e_entry \
+ $$($(ELFEDIT) -re 'sym:st_value -osimple __vsyscall' $(DYNLIB))" \
+ $(DYNLIB)
+
+all: entryfix
+
+install: all $(ROOTLIBS)
diff --git a/usr/src/lib/brand/lx/lx_vdso/i386/vdso_subr.s b/usr/src/lib/brand/lx/lx_vdso/i386/vdso_subr.s
new file mode 100644
index 0000000000..ed7be8bb23
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/i386/vdso_subr.s
@@ -0,0 +1,92 @@
+/*
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+
+#include <sys/asm_linkage.h>
+#include <sys/lx_syscalls.h>
+
+
+#if defined(lint)
+
+comm_page_t *
+__vdso_find_commpage()
+{}
+
+long
+__vdso_sys_clock_gettime(uint_t clock_id, timespec_t *tp)
+{}
+
+int
+__vdso_sys_gettimeofday(timespec_t *tp, struct lx_timezone *tz)
+{}
+
+time_t
+__vdso_sys_time(timespec_t *tp)
+{}
+
+#else /* lint */
+
+ ENTRY_NP(__vdso_find_commpage)
+ call 1f
+1: popl %eax
+ andl $LX_VDSO_ADDR_MASK, %eax
+ addl $LX_VDSO_SIZE, %eax
+ ret
+ SET_SIZE(__vdso_find_commpage)
+
+ ENTRY_NP(__vdso_sys_clock_gettime)
+ movl $LX_SYS_clock_gettime, %eax
+ movl 0x4(%esp), %ebx
+ movl 0x8(%esp), %ecx
+ int $0x80
+ ret
+ SET_SIZE(__vdso_sys_clock_gettime)
+
+ ENTRY_NP(__vdso_sys_gettimeofday)
+ movl $LX_SYS_gettimeofday, %eax
+ movl 0x4(%esp), %ebx
+ movl 0x8(%esp), %ecx
+ int $0x80
+ ret
+ SET_SIZE(__vdso_sys_gettimeofday)
+
+ ENTRY_NP(__vdso_sys_time)
+ movl $LX_SYS_time, %eax
+ movl 0x4(%esp), %ebx
+ int $0x80
+ ret
+ SET_SIZE(__vdso_sys_time)
+
+ ENTRY_NP(__vsyscall)
+ /*
+ * On 32-bit Linux, the VDSO entry point (specified by e_entry)
+ * provides a potentially accelerated means to vector into the kernel.
+ * Normally this means using 'sysenter' with a Linux-custom calling
+ * convention so programs expecting int80 behavior are not required to
+ * change how arguments are passed.
+ *
+ * The SunOS sysenter entry point does _not_ tolerate such a departure
+ * from convention, so if this function is updated to use sysenter, it
+ * must properly marshal arguments onto the stack from the int80 style.
+ * Such an enhancement can only occur once sysenter receives the same
+ * branding hooks as syscall and int80.
+ */
+ int $0x80
+ ret
+ SET_SIZE(__vsyscall)
+
+#endif /* lint */
diff --git a/usr/src/lib/brand/lx/lx_vdso/tools/Makefile b/usr/src/lib/brand/lx/lx_vdso/tools/Makefile
new file mode 100644
index 0000000000..7907aa67c4
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/tools/Makefile
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+PROG = vdso_tool
+
+include ../../../../../cmd/Makefile.cmd
+
+OBJS = vdso_tool.o
+
+CLOBBERFILES += $(PROG)
+
+NATIVECC_CFLAGS += $(CFLAGS) $(CCVERBOSE)
+NATIVECC_LDLIBS += -lelf
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all
+
+lint: lint_PROG
+
+clean:
+ $(RM) $(OBJS)
+
+$(PROG): $(OBJS)
+ $(NATIVECC) $(NATIVECC_CFLAGS) $(NATIVECC_LDLIBS) $(OBJS) -o $@
+ $(POST_PROCESS)
+
+include ../../../../../cmd/Makefile.targ
diff --git a/usr/src/lib/brand/lx/lx_vdso/tools/vdso_tool.c b/usr/src/lib/brand/lx/lx_vdso/tools/vdso_tool.c
new file mode 100644
index 0000000000..0e1d99f9da
--- /dev/null
+++ b/usr/src/lib/brand/lx/lx_vdso/tools/vdso_tool.c
@@ -0,0 +1,388 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * vdso_tool: a build-time tool for adjusting properties of the "lx_vdso.so.1"
+ * object we build for VDSO emulation in the LX brand.
+ *
+ * This tool ensures that the shared object contains only one loadable program
+ * header (PT_LOAD), and extends the size of that program header to induce the
+ * loading of all sections into memory. It also sets a few attributes in the
+ * ELF header.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <libelf.h>
+#include <gelf.h>
+
+#define PROG "vdso_tool"
+
+typedef enum vdso_flags {
+ VDSO_UNLINK = 0x0001,
+ VDSO_UPDATE = 0x0002
+} vdso_flags_t;
+
+typedef struct vdso {
+ int v_fd;
+ char *v_path;
+ Elf *v_elf;
+ vdso_flags_t v_flags;
+ int v_ptload_phdr;
+ Elf64_Off v_max_offset;
+} vdso_t;
+
+static int
+open_vdso(vdso_t **vp, char *path)
+{
+ vdso_t *v;
+
+ if ((v = calloc(1, sizeof (vdso_t))) == NULL ||
+ (v->v_path = strdup(path)) == NULL) {
+ err(1, "could not allocate memory");
+ }
+ v->v_ptload_phdr = -1;
+ v->v_fd = -1;
+ *vp = v;
+
+ /*
+ * Open shared object file.
+ */
+ if ((v->v_fd = open(v->v_path, O_RDWR)) == -1) {
+ (void) fprintf(stderr, "could not open: %s: %s\n", v->v_path,
+ strerror(errno));
+ return (-1);
+ }
+
+ /*
+ * Attach libelf.
+ */
+ if ((v->v_elf = elf_begin(v->v_fd, ELF_C_RDWR, NULL)) == NULL) {
+ (void) fprintf(stderr, "could not attach libelf: %s\n",
+ elf_errmsg(-1));
+ return (-1);
+ }
+
+ if (elf_kind(v->v_elf) != ELF_K_ELF) {
+ (void) fprintf(stderr, "wrong elf type\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+close_vdso(vdso_t *v)
+{
+ int rval = 0;
+
+ if (v == NULL) {
+ return (0);
+ }
+
+ if (v->v_elf != NULL) {
+ /*
+ * If we want to write to the file, do so now.
+ */
+ if (v->v_flags & VDSO_UPDATE) {
+ if (elf_update(v->v_elf, ELF_C_WRITE) == -1) {
+ (void) fprintf(stderr, "ERROR: elf_update "
+ "failed: %s\n", elf_errmsg(-1));
+ v->v_flags |= VDSO_UNLINK;
+ rval = -1;
+ }
+ }
+
+ /*
+ * Close the libelf handle for this file.
+ */
+ if (elf_end(v->v_elf) == -1) {
+ (void) fprintf(stderr, "ERROR: elf_end failed: %s\n",
+ elf_errmsg(-1));
+ v->v_flags |= VDSO_UNLINK;
+ rval = -1;
+ }
+ }
+
+ if (v->v_fd > 0) {
+ (void) close(v->v_fd);
+ }
+
+ if (v->v_flags & VDSO_UNLINK) {
+ (void) fprintf(stderr, "unlinking file: %s\n", v->v_path);
+ if (unlink(v->v_path) != 0) {
+ (void) fprintf(stderr, "unlink failed: %s\n",
+ strerror(errno));
+ rval = -1;
+ }
+ }
+
+ free(v->v_path);
+ free(v);
+
+ return (rval);
+}
+
+static int
+adjust_elf_ehdr(vdso_t *v)
+{
+ GElf_Ehdr ehdr;
+ boolean_t dirty = B_FALSE;
+
+ if (gelf_getehdr(v->v_elf, &ehdr) == NULL) {
+ (void) fprintf(stderr, "could not get ehdr: %s\n",
+ elf_errmsg(-1));
+ goto errout;
+ }
+
+ if (ehdr.e_ident[EI_OSABI] != ELFOSABI_NONE) {
+ (void) fprintf(stdout, "set EI_OSABI = ELFOSABI_NONE\n");
+ ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE;
+ dirty = B_TRUE;
+ }
+
+ if (ehdr.e_ident[EI_ABIVERSION] != 0) {
+ (void) fprintf(stdout, "set EI_ABIVERSION = 0\n");
+ ehdr.e_ident[EI_ABIVERSION] = 0;
+ dirty = B_TRUE;
+ }
+
+ if (dirty && gelf_update_ehdr(v->v_elf, &ehdr) == 0) {
+ (void) fprintf(stderr, "could not update ehdr: %s\n",
+ elf_errmsg(-1));
+ goto errout;
+ }
+
+ v->v_flags |= VDSO_UPDATE;
+ return (0);
+
+errout:
+ v->v_flags |= VDSO_UNLINK;
+ return (-1);
+}
+
+static int
+find_pt_load_phdr(vdso_t *v)
+{
+ size_t nphdr, nloadable = 0;
+ int i;
+
+ if (elf_getphdrnum(v->v_elf, &nphdr) != 0) {
+ (void) fprintf(stderr, "could not get phdr count: %s\n",
+ elf_errmsg(-1));
+ goto errout;
+ }
+ (void) fprintf(stdout, "phdr count: %d\n", nphdr);
+
+ for (i = 0; i < nphdr; i++) {
+ GElf_Phdr phdr;
+
+ if (gelf_getphdr(v->v_elf, i, &phdr) == NULL) {
+ (void) fprintf(stderr, "could not get phdr[%d] count: "
+ "%s\n", i, elf_errmsg(-1));
+ goto errout;
+ }
+
+ if (phdr.p_type == PT_LOAD) {
+ if (nloadable++ != 0) {
+ (void) fprintf(stderr, "multiple PT_LOAD "
+ "phdrs\n");
+ goto errout;
+ }
+
+ (void) fprintf(stdout, "PT_LOAD header is phdr[%d]\n",
+ i);
+ v->v_ptload_phdr = i;
+
+ if (phdr.p_filesz != phdr.p_memsz) {
+ (void) fprintf(stderr, "mismatched filesz "
+ "(%llx) and memsz (%llx)\n", phdr.p_filesz,
+ phdr.p_memsz);
+ goto errout;
+ }
+
+ if (phdr.p_filesz == 0) {
+ (void) fprintf(stderr, "filesz was zero\n");
+ goto errout;
+ }
+ }
+ }
+
+ return (0);
+
+errout:
+ v->v_flags |= VDSO_UNLINK;
+ return (-1);
+}
+
+static int
+find_maximum_offset(vdso_t *v)
+{
+ size_t nshdr;
+ int i;
+
+ if (elf_getshdrnum(v->v_elf, &nshdr) != 0) {
+ (void) fprintf(stderr, "could not get shdr count: %s\n",
+ elf_errmsg(-1));
+ v->v_flags |= VDSO_UNLINK;
+ return (-1);
+ }
+ (void) fprintf(stdout, "shdr count: %d\n", nshdr);
+
+ for (i = 0; i < nshdr; i++) {
+ Elf_Scn *scn = elf_getscn(v->v_elf, i);
+ GElf_Shdr shdr;
+ Elf64_Off end;
+
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ (void) fprintf(stderr, "could not get shdr[%d] "
+ "count: %s\n", i, elf_errmsg(-1));
+ goto errout;
+ }
+
+ end = shdr.sh_offset + shdr.sh_size;
+
+ if (end > v->v_max_offset) {
+ v->v_max_offset = end;
+ }
+ }
+
+ (void) fprintf(stdout, "maximum offset: %llx\n", v->v_max_offset);
+
+ return (0);
+
+errout:
+ v->v_flags |= VDSO_UNLINK;
+ return (-1);
+}
+
+static int
+update_pt_load_size(vdso_t *v)
+{
+ GElf_Phdr phdr;
+
+ if (gelf_getphdr(v->v_elf, v->v_ptload_phdr, &phdr) == NULL) {
+ (void) fprintf(stderr, "could not get phdr[%d] count: %s\n",
+ v->v_ptload_phdr, elf_errmsg(-1));
+ goto errout;
+ }
+
+ (void) fprintf(stdout, "PT_LOAD size is currently %llx\n",
+ phdr.p_filesz);
+ if (phdr.p_filesz < v->v_max_offset) {
+ (void) fprintf(stdout, "extending PT_LOAD size from %llx "
+ "to %llx\n", phdr.p_filesz, v->v_max_offset);
+
+ phdr.p_memsz = phdr.p_filesz = v->v_max_offset;
+
+ if (gelf_update_phdr(v->v_elf, v->v_ptload_phdr, &phdr) ==
+ NULL) {
+ (void) fprintf(stderr, "could not update PT_LOAD "
+ "phdr: %s", elf_errmsg(-1));
+ goto errout;
+ }
+
+ v->v_flags |= VDSO_UPDATE;
+ }
+
+ return (0);
+
+errout:
+ v->v_flags |= VDSO_UNLINK;
+ return (-1);
+}
+
+int
+main(int argc, char **argv)
+{
+ vdso_t *v;
+ char *filen = NULL;
+ int errflg = 0;
+ int c;
+ int status = 0;
+ boolean_t do_update = B_TRUE;
+
+ while ((c = getopt(argc, argv, ":nf:")) != -1) {
+ switch (c) {
+ case 'n':
+ do_update = B_FALSE;
+ break;
+ case 'f':
+ filen = optarg;
+ break;
+ case ':':
+ (void) fprintf(stderr, "option -%c requires an "
+ "operand\n", optopt);
+ errflg++;
+ break;
+ case '?':
+ (void) fprintf(stderr, "unrecognised option: -%c\n",
+ optopt);
+ errflg++;
+ break;
+ }
+ }
+
+ if (errflg != 0 || optind != argc || filen == NULL) {
+ (void) fprintf(stderr, "usage: %s -f <vdso.so>\n", PROG);
+ return (1);
+ }
+
+ (void) fprintf(stdout, "vdso file: %s\n", filen);
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ (void) fprintf(stderr, "libelf mismatch: %s\n", elf_errmsg(-1));
+ return (2);
+ }
+
+ status = 3;
+ if (open_vdso(&v, filen) == -1) {
+ goto out;
+ }
+
+ status++;
+ if (adjust_elf_ehdr(v) == -1) {
+ goto out;
+ }
+
+ status++;
+ if (find_pt_load_phdr(v) == -1) {
+ goto out;
+ }
+
+ status++;
+ if (find_maximum_offset(v) == -1) {
+ goto out;
+ }
+
+ status++;
+ if (do_update && update_pt_load_size(v) == -1) {
+ goto out;
+ }
+
+out:
+ status++;
+ if (close_vdso(v) == 0) {
+ status = 0;
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/brand/lx/netfiles/Makefile b/usr/src/lib/brand/lx/netfiles/Makefile
new file mode 100644
index 0000000000..1d15d69850
--- /dev/null
+++ b/usr/src/lib/brand/lx/netfiles/Makefile
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
+#
+
+TXTS = etc_default_nfs
+NFS_DFL = ../../../../cmd/fs.d/nfs/etc/nfs.dfl
+
+all: $(TXTS)
+
+include ../Makefile.lx
+
+lint:
+
+install: $(ROOTTXTS)
+
+clean:
+ -$(RM) etc_default_nfs
+
+clobber: clean
+ -$(RM) $(ROOTXMLDOCS) $(ROOTTXTS)
+
+etc_default_nfs: $(NFS_DFL)
+ $(RM) $@
+ $(CP) $(NFS_DFL) $@
diff --git a/usr/src/lib/brand/lx/testing/Makefile b/usr/src/lib/brand/lx/testing/Makefile
new file mode 100644
index 0000000000..9149929b60
--- /dev/null
+++ b/usr/src/lib/brand/lx/testing/Makefile
@@ -0,0 +1,36 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+TXTS = ltp_skiplist ltp_tests pts_ignorelist
+
+all:
+
+include $(SRC)/cmd/Makefile.cmd
+include ../Makefile.lx
+
+all := TARGET= all
+install := TARGET= install
+clobber := TARGET= clobber
+
+install: $(ROOTTXTS)
+
+_msg:
+
+lint:
+
+clean:
+
+clobber:
+ -$(RM) $(ROOTTXTS)
diff --git a/usr/src/lib/brand/lx/testing/Readme_ltp b/usr/src/lib/brand/lx/testing/Readme_ltp
new file mode 100644
index 0000000000..4a2fcd353b
--- /dev/null
+++ b/usr/src/lib/brand/lx/testing/Readme_ltp
@@ -0,0 +1,294 @@
+The Linux Test Project (LTP) provides the basis for testing the lx API
+implementation. The project webpage is at http://linux-test-project.github.io/
+and the source is available on GitHub at
+https://github.com/linux-test-project/ltp.git.
+
+LTP should be built and run from within an lx zone.
+
+To build
+--------
+As root first make sure you have the tools installed:
+ apt-get install build-essential autoconf automake git quota
+
+For 64-bit:
+ apt-get install libc6-dev-i386
+
+Additional prerequisites are required activate some tests:
+ apt-get install attr-dev libaio-dev
+
+As a normal user:
+ git clone https://github.com/linux-test-project/ltp.git
+ cd ltp
+ make autotools
+ ./configure
+ make all
+
+As root:
+ make install
+
+The tests can be built in both a zone that has been installed with a 32-bit
+version of Linux and another zone that has been installed with a 64-bit version
+of the same release. When testing the 64-bit zone, a copy of the 32-bit build
+can be run in the 64-bit zone to ensure that 32-bit applications work
+correctly on a 64-bit install.
+
+Running the tests
+-----------------
+The LTP source tree provides detailed documentation on using the test suite, so
+this readme only give a short summary.
+
+Because many of the tests are targetted at kernel functionality which does not
+apply to Illumos, or test capabilities which are not available from within a
+zone, or test system call functionality which has not yet been completed, a
+skip list is used during the test run to bypass tests which are known to fail.
+
+The skip list lives in this directory and is delivered on the system. It is
+available from within the lx zone as /native/usr/lib/brand/lx/ltp_skiplist. As
+new functionality is completed, the skip list should be updated to remove tests
+which now work.
+
+As root:
+ cd /opt/ltp
+ /opt/ltp/runltp -f `cat /native/usr/lib/brand/lx/ltp_tests` \
+ -S /native/usr/lib/brand/lx/ltp_skiplist -p >/tmp/test.log
+
+When the test run has finished, the results will be logged in a date/time
+stamped file under /opt/ltp/results. The summary at the end of the log file
+should show "Total Failures: 0". If not, something is wrong.
+
+Running tests for development
+-----------------------------
+The source for the tests can be found under the testcases directory. The
+largest and most useful set for lx live under testcases/kernel/syscalls.
+
+For development purposes, an individual test (or tests) can be run by listing
+them in a command file, one per line. For example, with a command file named
+~/tcmds, to run the read01 test you setup the file so it looks like this:
+ read01 read01
+
+You can run that specific test as follows:
+ /opt/ltp/runltp -f ~/tcmds -p -l ~/read.log
+
+Test status
+-----------
+This section provides a short summary of the rationale for why tests are being
+skipped.
+
+LTP groups tests into command files (i.e. syscalls, nptl, etc. provided with
+the -f option in the runltp command shown above). A complete list of the groups
+can be seen in LTP source tree under the runtest directory. Some of these
+groups are obviously not applicable when running in an lx zone. The remaining
+groups still need work before they can be run. The groups shown in the runltp
+command above are expected to work when the skip list is used. The 'syscalls'
+command file runs the majority of the actual system call tests which we are
+interested in.
+
+The following table indicates why specific subtests are being skipped. Also
+note that the following tests pass in a 64-bit lx zone, but fail in a zone
+installed with a 32-bit Linux build: mmap15, open12, openat02 and sendfile09.
+
+ Legend:
+ x = never in a zone
+ * = fails on kvm and bare metal too
+ # = emulation not implemented yet
+ - = could enable with a test zone config change
+
+- access06 wants a block device
+x acct01 enables bsd process accounting
+# add_key01
+# add_key02
+x adjtimex01
+x adjtimex02
+x bdflush01
+x cacheflush01
+x chmod03 need PRIV_SYS_CONFIG to set sticky bit on reg file
+- chmod06 needs dev
+x chmod07 need PRIV_SYS_CONFIG to set sticky bit on reg file
+- chown04 needs dev
+- chown04_16 needs dev
+# clone02
+# clone08
+- creat06 wants to mount a ro fs
+x creat07 we don't behave this way for ETXTBSY
+x creat08 sets euid to 'nobody', loses PRIV_FILE_SETID to set sgid
+x execve04 we don't behave this way for ETXTBSY
+# fallocate01
+# fallocate02
+# fallocate03
+x fchmod02 need PRIV_SYS_CONFIG to set sticky bit on reg file
+x fchmod03 need PRIV_SYS_CONFIG to set sticky bit on reg file
+- fchmod06 needs dev
+# fchown04 mounts
+# fchown04_16
+# fcntl06 not supported on linux
+# fcntl06_64
+# fcntl23 leases not implemented
+# fcntl23_64 "
+# fcntl24 "
+# fcntl24_64 "
+# fcntl25 "
+# fcntl25_64 "
+# fcntl26 "
+# fcntl26_64 "
+# fcntl30
+# fcntl30_64
+# fcntl31 setown/getown not impl
+# fcntl31_64
+# fcntl32 F_SETLEASE not impl
+# fcntl32_64
+# fcntl33 F_SETLEASE not impl
+# fcntl33_64
+# fork05 asm into %fs reg
+- fork09 needs a swap cap of ~9GB
+# fork13 decided not to support this
+# fork14 "
+# ftruncate04 need a mnt with mandatory locking
+# ftruncate04_64
+# getdents02 wrong errno on test 4 - perf. impact too high
+# getdents02_64
+# get_mempolicy01
+x getrusage03 we don't fill in the ru_maxrss field
+- getxattr01 need attr/xattr.h at build time
+- getxattr02
+- getxattr03
+# ioctl03 needs /dev/net/tun
+# io_cancel01 libaio stuff not done
+# io_destroy01
+# io_getevents01
+# io_setup01
+# io_submit01
+- inotify03 needs dev
+# fanotify01 don't have fanotify
+# fanotify02
+# fanotify03
+# fanotify04
+# fanotify05
+# keyctl01 no kernel keyring support
+- lchown03 needs to mount ro fs
+- lchown03_16
+- linkat02 needs dev
+- link08 needs dev
+x mem01 crashme test which expects OOM killer to save the day
+- mkdir03 needs dev
+- mkdirat02 needs dev
+x mknod01 makes block and chr devs
+- mknod07 needs dev
+- mknodat02 needs dev
+# mmap13 expects "invalid access" to SIGBUS
+- mount01 needs dev
+- mount02 needs dev
+x mount03 mounts ext2
+- mount04 needs dev
+x mount05 mounts ext2
+x mount06 mounts ext2
+# mq_notify01
+# mq_notify02
+# mq_open01
+# mq_timedreceive01
+# mq_timedsend01
+# mq_unlink01
+x mremap01
+x mremap02
+x mremap03
+x mremap04
+x mremap05
+# msgctl12 uses MSG_STAT
+# msgrcv07 MSG_EXCEPT subtest - not avail.
+x open01 need PRIV_SYS_CONFIG to set sticky bit on reg file
+# open02 expects NOATIME to cause err for unpriv user
+# open10 setgid on sgid subdir behavior
+x open11 makes device
+# ppoll01
+# process_vm_readv01
+# process_vm_readv02
+# process_vm_readv03
+# process_vm_writev01
+# process_vm_writev02
+# prot_hsymlinks /proc/sys/fs/protected_hardlinks
+x ptrace04 not supp on our arch
+# ptrace05 OS-3307
+# read02 checks errno for O_DIRECT
+# readahead01
+# readahead02
+# readdir21 dir perf. issue
+- rename11 needs dev
+- renameat01 needs dev
+- rmdir02 needs dev
+x sched_getparam01 assumes Linux SCHED_OTHER return value
+x sched_getparam02 assumes Linux SCHED_OTHER return value
+# sched_rr_get_interval01
+# sched_rr_get_interval02
+# sched_rr_get_interval03
+x sched_setparam02 tries to set Linux policies
+x sched_setparam03 tries to set Linux policies
+# sched_getscheduler01
+# sched_getscheduler02
+x sched_setscheduler01
+x sched_setaffinity01
+x sched_getaffinity01
+# semctl01 all pass but SEM_STAT - linux specific
+# semop02 last test fails errno - expensive
+# sendfile02 OS-3296
+# sendfile02_64 "
+# sendfile04 "
+# sendfile04_64 "
+# sendfile06 "
+# sendfile06_64 "
+# sendfile07 "
+# sendfile07_64 "
+sendmsg01 OS-3295 - tests actually pass
+x setfsuid04 no real equiv. and only for NFS server
+x setfsuid04_16
+# sgetmask01 obsolete
+# setgroups04_16 expects sig11 for certain err
+# setns01
+# setns02
+# setpgid02 all pass but one, expects pid 0 to be there
+* setregid02 fails on bare metal, expects to lookup group "nobody" which
+* setregid02_16 doesn't exist. it is "nogroup" on ubuntu at least
+# setrlimit01 all pass but one, expects to set proc limit
+x settimeofday01
+# setxattr01
+# setxattr02
+# setxattr03
+# shmget05 OS-3326
+# splice01
+# splice02
+# splice03
+# tee01
+# tee02
+# ssetmask01 obsolete
+x stime01
+x switch01
+# sync_file_range01
+# sysconf01 most pass but see OS-3305
+# sysctl01 the build compiled this out,
+# sysctl03 this syscall is basically obsolete
+# sysctl04 obsolete
+# sysctl05
+# syslog01
+# syslog02
+# syslog03
+# syslog04
+# syslog05
+# syslog06
+# syslog07
+# syslog08
+# syslog09
+# syslog10
+# syslog11
+# syslog12
+# unshare01
+# unshare02
+- umount01 needs dev
+- umount02 needs dev
+- umount03 needs dev
+x ustat01 obsolete call to stat FS
+x ustat02 obsolete call to stat FS
+- utime06 needs dev
+- utimes01 needs dev
+# utimensat01 many subtests pass but see OS-3328 for the rest
+# vmsplice01
+# vmsplice02
+# perf_event_open01
+# perf_event_open02
diff --git a/usr/src/lib/brand/lx/testing/ltp_skiplist b/usr/src/lib/brand/lx/testing/ltp_skiplist
new file mode 100644
index 0000000000..571717b23a
--- /dev/null
+++ b/usr/src/lib/brand/lx/testing/ltp_skiplist
@@ -0,0 +1,269 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2017 Joyent, Inc.
+
+# Broken tests
+poll02 # OS-3997
+
+# tests functionality not allowed in a zone
+accept4_01
+acct01
+adjtimex01
+adjtimex02
+bdflush01
+cacheflush01
+chmod03
+chmod07
+creat07
+creat08
+execve04
+fchmod02
+fchmod03
+getrusage03
+ioperm01
+ioperm02
+iopl01
+iopl02
+isofs
+mbind01
+mem01
+migrate_pages01
+migrate_pages02
+mknod01
+mmap12
+mount03
+mount05
+mount06
+modify_ldt01
+modify_ldt02
+move_pages01
+move_pages02
+move_pages03
+move_pages04
+move_pages05
+move_pages06
+move_pages07
+move_pages08
+move_pages09
+move_pages10
+move_pages11
+mremap01
+mremap02
+mremap03
+mremap04
+mremap05
+open01
+open11
+ptrace04
+quotactl01
+quotactl02
+remap_file_pages01
+remap_file_pages02
+setfsuid04
+setfsuid04_16
+settimeofday01
+stime01
+swapoff02
+swapon02
+swapon03
+switch01
+ustat01
+ustat02
+
+# needs a config with a dev or mounting
+# As of February 2017, an increasing number of tests require device support
+# (often via a zeroed file mounted via loopback) to function properly.
+access04
+chmod06
+chown04
+chown04_16
+creat06
+fchmod06
+fchown04
+fchown04_16
+inotify03
+lchown03
+lchown03_16
+linkat02
+link08
+madvise06
+mkdir03
+mkdirat02
+mknod07
+mknodat02
+mmap16
+mount01
+mount02
+mount04
+rename11
+renameat01
+rmdir02
+umount01
+umount02
+umount2_01
+umount2_02
+umount2_03
+umount03
+utime06
+utimes01
+
+# These tests are broken on 32-bit (including on "real" Linux)
+preadv01
+preadv02
+pwritev01
+pwritev02
+
+# tests functionality not implemented yet
+access06
+add_key01
+add_key02
+clone02
+clone08
+clone09
+crash02
+dirtyc0w
+fallocate04 # needs SEEK_HOLE
+fanotify01
+fanotify02
+fanotify03
+fanotify04
+fanotify05
+fanotify06
+fcntl06
+fcntl23
+fcntl23_64
+fcntl24
+fcntl24_64
+fcntl25
+fcntl25_64
+fcntl26
+fcntl26_64
+fcntl31
+fcntl31_64
+fcntl32
+fcntl32_64
+fcntl33
+fcntl33_64
+fork05
+fork09
+fork13
+fork14
+ftruncate04
+ftruncate04_64
+futex_wake04 # OS-4471
+getdents02
+getdents02_64
+get_mempolicy01
+getxattr01
+getxattr02
+getxattr03
+getxattr04
+ioctl03
+ioctl04
+ioctl05
+ioctl06
+keyctl01
+kcmp01
+kcmp02
+kcmp03
+lgetxattr01
+lgetxattr02
+llistxattr01
+llistxattr02
+llistxattr03
+madvise08 # no MADV_DONTDUMP support (yet?)
+mmap13
+mq_notify01
+mq_notify02
+mq_open01
+mq_timedreceive01
+mq_timedsend01
+mq_unlink01
+msgctl12
+msgrcv07
+msync04
+open02
+open10
+perf_event_open01
+perf_event_open02
+ppoll01
+process_vm_readv01
+process_vm_readv02
+process_vm_readv03
+process_vm_writev01
+process_vm_writev02
+prot_hsymlinks
+pty01 # OS-5437
+read02
+readahead01
+readahead02
+readdir2
+readdir21
+removexattr01
+removexattr02
+request_key01
+request_key02
+semctl01
+semop02
+sendfile02 # OS-3296
+sendfile02_64
+sendfile04
+sendfile04_64
+sendfile06
+sendfile06_64
+sendfile07
+sendfile07_64
+sendmsg01
+sendto02 # OS-5764
+setgroups04_16
+setns01
+setns02
+setpgid02
+setregid02
+setregid02_16
+setrlimit01
+setxattr01
+setxattr02
+setxattr03
+sgetmask01
+shmget05 # OS-3326
+splice01
+splice02
+splice03
+splice04
+splice05
+ssetmask01
+sync_file_range01
+sysconf01 # OS-3305
+sysctl01
+sysctl03
+sysctl04
+sysctl05
+syslog01
+syslog02
+syslog03
+syslog04
+syslog05
+syslog06
+syslog07
+syslog08
+syslog09
+syslog10
+syslog11
+syslog12
+tee01
+tee02
+unshare01
+utimensat01 # OS-3328
+unshare02
+vmsplice01
+vmsplice02
diff --git a/usr/src/lib/brand/lx/testing/ltp_tests b/usr/src/lib/brand/lx/testing/ltp_tests
new file mode 100644
index 0000000000..86e9725638
--- /dev/null
+++ b/usr/src/lib/brand/lx/testing/ltp_tests
@@ -0,0 +1 @@
+syscalls,nptl,ipc,pipes,pty,crashme,math
diff --git a/usr/src/lib/brand/lx/testing/pts_ignorelist b/usr/src/lib/brand/lx/testing/pts_ignorelist
new file mode 100644
index 0000000000..2c4f307b55
--- /dev/null
+++ b/usr/src/lib/brand/lx/testing/pts_ignorelist
@@ -0,0 +1,366 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+# Copyright 2016 Joyent, Inc.
+
+# The Open POSIX Test Suite (PTS) tests the POSIX conformance of an
+# operating system. A test may have one of six different results:
+#
+# o PASS: the test passed
+# o FAIL: the test failed
+# o UNRESOLVED: the test was unable to determine pass/fail
+# o UNSUPPORTED: this feature is not supported by the OS
+# o UNTESTED: this test is not yet implemented
+#
+# You can read more about these result codes in:
+#
+# ltp/testcases/open_posix_testsuite/Documentation/HOWTO_ResultCodes
+#
+# This file (pts_ignorelist) contains a list of tests which are known
+# not to pass on lx-brand zones, along with the expected test result.
+# These tests are grouped based on the reason for their failure,
+# described by the comment above the grouping. Ideally, any test
+# resulting in FAILED indicates a bug in lx-brand, but PTS is not
+# ideal. Many of the tests will return FAILED when they should return
+# UNRESOLVED instead. E.g., some of the MQ tests will return FAILED if
+# mq_open() fails while some will return UNRESOLVED. Unless otherwise
+# noted in the group comment, assume FAILED is a true bug (as opposed
+# to a lack of support by lx-brand).
+#
+# To run the tests and check your results against this list:
+#
+# cd ltp/testcases/open_posix_testsuite
+# make
+# make test 2>&1 | tee pts.log
+# diff <(egrep -v '^#|^$' /native/usr/lib/brand/lx/pts_ignorelist | sort) \
+# <(grep execution pts.log | tr -d : | awk '{ print $1, $3 }' | sort)
+#
+# Any delta reported by the diff is either a regression in lx-brand or
+# a change in the test code.
+
+#
+# POSIX message queues are not implemented in lx-brand. In illumos,
+# MQs are implemented completely in libc. In Linux, MQs are
+# implemented as system calls. The lx-brand code returns ENOSYS for
+# all the MQ system calls. The MQ tests are not consistent in how they
+# classify a failed mq_open() and thus the tests return a mixture of
+# UNRESOLVED and FAILED.
+#
+conformance/interfaces/fork/fork_19-1 UNRESOLVED
+conformance/interfaces/mq_close/mq_close_1-1 UNRESOLVED
+conformance/interfaces/mq_close/mq_close_2-1 UNRESOLVED
+conformance/interfaces/mq_close/mq_close_3-1 UNRESOLVED
+conformance/interfaces/mq_close/mq_close_4-1 UNRESOLVED
+conformance/interfaces/mq_getattr/mq_getattr_2-1 UNRESOLVED
+conformance/interfaces/mq_getattr/mq_getattr_2-2 UNRESOLVED
+conformance/interfaces/mq_getattr/mq_getattr_3-1 UNRESOLVED
+conformance/interfaces/mq_getattr/mq_getattr_4-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_1-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_2-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_3-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_4-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_5-1 UNRESOLVED
+conformance/interfaces/mq_notify/mq_notify_8-1 FAILED
+conformance/interfaces/mq_notify/mq_notify_9-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_1-1 FAILED
+conformance/interfaces/mq_open/mq_open_11-1 FAILED
+conformance/interfaces/mq_open/mq_open_12-1 FAILED
+conformance/interfaces/mq_open/mq_open_13-1 FAILED
+conformance/interfaces/mq_open/mq_open_15-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_16-1 FAILED
+conformance/interfaces/mq_open/mq_open_18-1 FAILED
+conformance/interfaces/mq_open/mq_open_19-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_2-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_20-1 FAILED
+conformance/interfaces/mq_open/mq_open_23-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_25-2 FAILED
+conformance/interfaces/mq_open/mq_open_27-1 FAILED
+conformance/interfaces/mq_open/mq_open_27-2 FAILED
+conformance/interfaces/mq_open/mq_open_29-1 FAILED
+conformance/interfaces/mq_open/mq_open_7-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_7-2 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_7-3 FAILED
+conformance/interfaces/mq_open/mq_open_8-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_8-2 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_9-1 UNRESOLVED
+conformance/interfaces/mq_open/mq_open_9-2 UNRESOLVED
+conformance/interfaces/mq_receive/mq_receive_1-1 FAILED
+conformance/interfaces/mq_receive/mq_receive_10-1 FAILED
+conformance/interfaces/mq_receive/mq_receive_11-1 FAILED
+conformance/interfaces/mq_receive/mq_receive_11-2 FAILED
+conformance/interfaces/mq_receive/mq_receive_12-1 FAILED
+conformance/interfaces/mq_receive/mq_receive_13-1 UNRESOLVED
+conformance/interfaces/mq_receive/mq_receive_2-1 UNRESOLVED
+conformance/interfaces/mq_receive/mq_receive_5-1 FAILED
+conformance/interfaces/mq_receive/mq_receive_7-1 UNRESOLVED
+conformance/interfaces/mq_receive/mq_receive_8-1 FAILED
+conformance/interfaces/mq_send/mq_send_1-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_10-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_11-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_11-2 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_12-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_13-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_14-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_2-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_3-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_3-2 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_4-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_4-2 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_4-3 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_5-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_5-2 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_7-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_8-1 UNRESOLVED
+conformance/interfaces/mq_send/mq_send_9-1 UNRESOLVED
+conformance/interfaces/mq_setattr/mq_setattr_1-1 UNRESOLVED
+conformance/interfaces/mq_setattr/mq_setattr_1-2 UNRESOLVED
+conformance/interfaces/mq_setattr/mq_setattr_2-1 UNRESOLVED
+conformance/interfaces/mq_setattr/mq_setattr_5-1 UNRESOLVED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_1-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_10-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_10-2 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_11-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_13-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_14-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_15-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_17-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_17-2 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_17-3 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_18-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_18-2 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_2-1 UNRESOLVED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_5-1 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_5-2 FAILED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_5-3 UNRESOLVED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_7-1 UNRESOLVED
+conformance/interfaces/mq_timedreceive/mq_timedreceive_8-1 FAILED
+conformance/interfaces/mq_timedsend/mq_timedsend_1-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_10-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_11-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_11-2 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_12-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_13-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_14-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_15-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_16-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_18-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_19-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_2-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_20-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_3-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_3-2 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_4-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_4-2 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_4-3 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_5-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_5-2 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_5-3 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_7-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_8-1 UNRESOLVED
+conformance/interfaces/mq_timedsend/mq_timedsend_9-1 UNRESOLVED
+conformance/interfaces/mq_unlink/mq_unlink_1-1 UNRESOLVED
+conformance/interfaces/mq_unlink/mq_unlink_2-1 UNRESOLVED
+conformance/interfaces/mq_unlink/mq_unlink_2-2 UNRESOLVED
+conformance/interfaces/mq_unlink/mq_unlink_7-1 FAILED
+functional/mqueues/mqueues_send_rev_1 UNRESOLVED
+functional/mqueues/mqueues_send_rev_2 UNRESOLVED
+
+#
+# Other features not implemented on Linux.
+#
+conformance/interfaces/pthread_rwlock_unlock/pthread_rwlock_unlock_4-1 UNSUPPORTED
+conformance/interfaces/pthread_rwlock_unlock/pthread_rwlock_unlock_4-2 UNSUPPORTED
+
+#
+# Part of this test is verifying specific thread scheduling and I'm
+# not sure how much I trust it. This test fails on native too.
+#
+conformance/interfaces/sched_setparam/sched_setparam_9-1 FAILED
+
+#
+# Linux doesn't support PTHREAD_SCOPE_PROCESS, see
+# pthread_attr_setscope(3).
+#
+conformance/interfaces/sched_setscheduler/sched_setscheduler_22-1 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_22-2 UNSUPPORTED
+
+#
+# These tests test specific scheduling behavior. They pass on native
+# when actually running in the RT class, but we run lx zones in the
+# FSS class and can't guarantee specific scheduling order.
+#
+conformance/interfaces/pthread_create/pthread_create_1-6 FAILED
+conformance/interfaces/sem_post/sem_post_8-1 FAILED
+
+#
+# It looks like we are missing some futex support that
+# pthread_mutex_timedlock() requires:
+#
+# futex(0x602820, FUTEX_LOCK_PI_PRIVATE, 1) = -1 ENOSYS
+#
+functional/threads/pi_test/pi_test_pitest-1 FAILED
+functional/threads/pi_test/pi_test_pitest-2 FAILED
+functional/threads/pi_test/pi_test_pitest-3 FAILED
+functional/threads/pi_test/pi_test_pitest-4 FAILED
+functional/threads/pi_test/pi_test_pitest-6 FAILED
+
+#
+# Another case where we need FUTEX_LOCK_PI, but slightly different
+# from the ones above. Glibc's implementation of pthread_mutex_lock()
+# doesn't check for ENOSYS from FUTEX_LOCK_PI and instead chugs along
+# assuming it has the mutex.
+#
+functional/threads/pi_test/pi_test_pitest-5 UNRESOLVED
+
+#
+# glibc doesn't support PTHREAD_SCOPE_PROCESS.
+#
+conformance/interfaces/sched_setparam/sched_setparam_20-1 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_21-1 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_21-2 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_15-1 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_15-2 UNSUPPORTED
+
+#
+# _POSIX_SPORADIC_SERVER is not available on Linux.
+#
+conformance/interfaces/sched_get_priority_max/sched_get_priority_max_1-3 UNSUPPORTED
+conformance/interfaces/sched_get_priority_min/sched_get_priority_min_1-3 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_23-2 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_23-3 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_23-4 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_23-5 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_25-2 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_25-3 UNSUPPORTED
+conformance/interfaces/sched_setparam/sched_setparam_25-4 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_17-2 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_17-3 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_17-4 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_19-2 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_19-3 UNSUPPORTED
+conformance/interfaces/sched_setscheduler/sched_setscheduler_19-4 UNSUPPORTED
+
+#
+# No semaphore limit (_SC_SEM_NSEMS_MAX).
+#
+conformance/interfaces/sem_init/sem_init_7-1 UNTESTED
+
+#
+# CLOCK_PROCESS_CPUTIME_ID/CLOCK_THREAD_CPUTIME_ID not supported.
+#
+conformance/interfaces/fork/fork_22-1 UNRESOLVED
+conformance/interfaces/timer_create/timer_create_10-1 UNRESOLVED
+
+#
+# Multiple instances of the same signal are coalesced on sigwait().
+#
+conformance/interfaces/sigwait/sigwait_2-1 FAILED
+
+#
+# Need sys_time privs.
+#
+# clock_settime_20-1 returns FAILED because it expects EINVAL but gets EPERM.
+#
+conformance/interfaces/clock_settime/clock_settime_1-1 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_4-1 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_4-2 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_5-1 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_5-2 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_7-1 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_7-2 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_8-1 UNRESOLVED
+conformance/interfaces/clock_settime/clock_settime_20-1 FAILED
+
+#
+# https://github.com/joyent/illumos-joyent/issues/66
+#
+conformance/interfaces/clock_getcpuclockid/clock_getcpuclockid_1-1 FAILED
+conformance/interfaces/clock_getcpuclockid/clock_getcpuclockid_1-2 UNRESOLVED
+conformance/interfaces/clock_getcpuclockid/clock_getcpuclockid_2-1 FAILED
+conformance/interfaces/clock_getcpuclockid/clock_getcpuclockid_5-1 UNRESOLVED
+
+#
+# Various AIO functions don't EINVAL on bogus struct aiocb.
+#
+# Faulty on lx brand, Linux on KVM, and illumos.
+#
+conformance/interfaces/aio_error/aio_error_3-1 UNTESTED
+conformance/interfaces/aio_return/aio_return_4-1 UNTESTED
+
+#
+# _SC_AIO_MAX == -1
+#
+conformance/interfaces/aio_read/aio_read_9-1 UNSUPPORTED
+conformance/interfaces/aio_write/aio_write_7-1 UNSUPPORTED
+
+#
+# PTS is a wasteland, these tests hard-coded to fail.
+#
+conformance/interfaces/aio_suspend/aio_suspend_5-1 UNSUPPORTED
+
+#
+# Tests that fail on lx-brand and Linux but pass illumos.
+#
+conformance/interfaces/aio_return/aio_return_2-1 UNTESTED
+conformance/interfaces/aio_return/aio_return_3-2 UNTESTED
+conformance/interfaces/pthread_rwlock_rdlock/pthread_rwlock_rdlock_2-1 FAILED
+conformance/interfaces/pthread_rwlock_rdlock/pthread_rwlock_rdlock_2-2 FAILED
+
+#
+# Tests that fail everywhere: lx-brand, Linux, and illumos.
+#
+conformance/interfaces/pthread_rwlock_unlock/pthread_rwlock_unlock_3-1 FAILED
+conformance/interfaces/sched_getparam/sched_getparam_6-1 UNTESTED
+conformance/interfaces/sched_getscheduler/sched_getscheduler_7-1 UNTESTED
+
+#
+# mmap() is supposed to return ENODEV for pipe but returns ENOSYS.
+# This is an illumos bug.
+#
+conformance/interfaces/mmap/mmap_23-1 FAILED
+
+#
+# I'm not sure.
+#
+conformance/interfaces/mmap/mmap_18-1 FAILED
+
+#
+# According to the spec "Memory access within the mapping but beyond
+# the current end of the underlying objects __may__ result in SIGBUS
+# signals being sent to the process". So I don't think it breaks POSIX
+# but it surely doesn't behave like Linux.
+#
+conformance/interfaces/mmap/mmap_11-2 FAILED
+
+#
+# The test uses /proc/mounts to check for noatime but the lx-brand
+# does not indicate noatime even if the underlying zfs fs has atime
+# disabled.
+#
+conformance/interfaces/mmap/mmap_13-1 FAILED
+
+#
+# Doesn't run on 64bit.
+#
+conformance/interfaces/mmap/mmap_31-1 UNSUPPORTED
+
+#
+# Bytes written past the end of the mmap object (but still in page)
+# are not written to disk but they do appear to persist in the page
+# when mmap'd by another pid. Perhaps this test is really testing an
+# implementation detail of Linux's VM system.
+#
+conformance/interfaces/mmap/mmap_11-4 FAILED
+
+#
+# lx-brand doesn't implement clock_getcpudclockid(pid,...).
+#
+conformance/interfaces/pthread_condattr_setclock/pthread_condattr_setclock_1-3 FAILED
diff --git a/usr/src/lib/brand/lx/zone/Makefile b/usr/src/lib/brand/lx/zone/Makefile
new file mode 100644
index 0000000000..4d681a1b45
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/Makefile
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2015 Joyent, Inc. All rights reserved.
+#
+
+PROGS = lx_boot
+PROGS += lx_boot_zone_redhat lx_boot_zone_ubuntu lx_boot_zone_debian
+PROGS += lx_boot_zone_busybox
+XMLDOCS = config.xml platform.xml
+TEMPLATES = SUNWlx.xml SUNWlx26.xml
+
+all: $(PROGS)
+
+include $(SRC)/cmd/Makefile.cmd
+include ../Makefile.lx
+
+all := TARGET= all
+install := TARGET= install
+clobber := TARGET= clobber
+
+POFILES= $(PROGS:%=%.po)
+POFILE= lx_zone.po
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(BUILDPO.pofiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+install: $(PROGS) $(ROOTXMLDOCS) $(ROOTTEMPLATES) $(ROOTPROGS)
+ mkdir -p $(ROOT)/usr/lib/brand/lx/ld/64
+ crle -c $(ROOT)/usr/lib/brand/lx/ld/ld.config \
+ -l /native/lib:/native/usr/lib \
+ -s /native/lib/secure:/native/usr/lib/secure
+ crle -64 -c $(ROOT)/usr/lib/brand/lx/ld/64/ld.config \
+ -l /native/lib/64:/native/usr/lib/64 \
+ -s /native/lib/secure/64:/native/usr/lib/secure/64
+
+lint:
+
+clean:
+ -$(RM) $(PROGS)
+
+clobber: clean
+ -$(RM) $(ROOTXMLDOCS) $(ROOTPROGS) $(ROOTTEMPLATES)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/brand/lx/zone/SUNWlx.xml b/usr/src/lib/brand/lx/zone/SUNWlx.xml
new file mode 100644
index 0000000000..04c38873de
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/SUNWlx.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ DO NOT EDIT THIS FILE. Use zonecfg(1M) instead.
+-->
+
+<!DOCTYPE zone PUBLIC "-//Sun Microsystems Inc//DTD Zones//EN" "file:///usr/share/lib/xml/dtd/zonecfg.dtd.1">
+
+<zone name="default" zonepath="" autoboot="false" brand="lx">
+</zone>
diff --git a/usr/src/lib/brand/lx/zone/SUNWlx26.xml b/usr/src/lib/brand/lx/zone/SUNWlx26.xml
new file mode 100644
index 0000000000..9bd8af4d92
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/SUNWlx26.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ DO NOT EDIT THIS FILE. Use zonecfg(1M) instead.
+-->
+
+<!DOCTYPE zone PUBLIC "-//Sun Microsystems Inc//DTD Zones//EN" "file:///usr/share/lib/xml/dtd/zonecfg.dtd.1">
+
+<zone name="default" zonepath="" autoboot="false" brand="lx">
+ <attr name="kernel-version" type="string" value="2.6"/>
+</zone>
diff --git a/usr/src/lib/brand/lx/zone/config.xml b/usr/src/lib/brand/lx/zone/config.xml
new file mode 100644
index 0000000000..ba7a150a2c
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/config.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright 2015, Joyent, Inc.
+
+ DO NOT EDIT THIS FILE.
+-->
+
+<!DOCTYPE brand PUBLIC "-//Sun Microsystems Inc//DTD Brands//EN"
+ "file:///usr/share/lib/xml/dtd/brand.dtd.1">
+
+<brand name="lx">
+ <modname>lx_brand</modname>
+
+ <initname>/native/usr/lib/brand/lx/lxinit</initname>
+ <login_cmd>/bin/login -h zone:%Z %u</login_cmd>
+ <forcedlogin_cmd>/bin/login -h zone:%Z -f %u</forcedlogin_cmd>
+ <user_cmd>/usr/bin/getent passwd %u</user_cmd>
+
+ <install>/usr/lib/brand/lx/lx_install %z %R</install>
+ <installopts>d:hsvX</installopts>
+ <boot>/usr/lib/brand/lx/lx_boot %z %R</boot>
+ <halt>/usr/lib/brand/lx/lx_support halt %R %z</halt>
+ <verify_cfg>/usr/lib/brand/lx/lx_support verify</verify_cfg>
+ <verify_adm></verify_adm>
+ <postclone></postclone>
+ <postinstall></postinstall>
+
+ <privilege set="default" name="contract_event" />
+ <privilege set="default" name="contract_identity" />
+ <privilege set="default" name="contract_observer" />
+ <privilege set="default" name="dtrace_proc" />
+ <privilege set="default" name="dtrace_user" />
+ <privilege set="default" name="file_chown" />
+ <privilege set="default" name="file_chown_self" />
+ <privilege set="default" name="file_dac_execute" />
+ <privilege set="default" name="file_dac_read" />
+ <privilege set="default" name="file_dac_search" />
+ <privilege set="default" name="file_dac_write" />
+ <privilege set="default" name="file_owner" />
+ <privilege set="default" name="file_setid" />
+ <privilege set="default" name="ipc_dac_read" />
+ <privilege set="default" name="ipc_dac_write" />
+ <privilege set="default" name="ipc_owner" />
+ <privilege set="default" name="net_bindmlp" />
+ <privilege set="default" name="net_icmpaccess" />
+ <privilege set="default" name="net_mac_aware" />
+ <privilege set="default" name="net_privaddr" />
+ <privilege set="default" name="net_rawaccess" ip-type="exclusive" />
+ <privilege set="default" name="proc_chroot" />
+ <privilege set="default" name="sys_audit" />
+ <privilege set="default" name="proc_audit" />
+ <privilege set="default" name="proc_lock_memory" />
+ <privilege set="default" name="proc_owner" />
+ <privilege set="default" name="proc_secflags" />
+ <privilege set="default" name="proc_setid" />
+ <privilege set="default" name="proc_prioup" />
+ <privilege set="default" name="proc_taskid" />
+ <privilege set="default" name="sys_acct" />
+ <privilege set="default" name="sys_admin" />
+ <privilege set="default" name="sys_ip_config" ip-type="exclusive" />
+ <privilege set="default" name="sys_iptun_config" ip-type="exclusive" />
+ <privilege set="default" name="sys_mount" />
+ <privilege set="default" name="sys_nfs" />
+ <privilege set="default" name="sys_resource" />
+ <privilege set="default" name="sys_ppp_config" ip-type="exclusive" />
+
+ <privilege set="prohibited" name="dtrace_kernel" />
+ <privilege set="prohibited" name="proc_zone" />
+ <privilege set="prohibited" name="sys_config" />
+ <privilege set="prohibited" name="sys_devices" />
+ <privilege set="prohibited" name="sys_ip_config" ip-type="shared" />
+ <privilege set="prohibited" name="sys_linkdir" />
+ <privilege set="prohibited" name="sys_net_config" />
+ <privilege set="prohibited" name="sys_ppp_config" ip-type="shared" />
+ <privilege set="prohibited" name="sys_res_config" />
+ <privilege set="prohibited" name="sys_suser_compat" />
+ <privilege set="prohibited" name="xvm_control" />
+ <privilege set="prohibited" name="virt_manage" />
+
+ <privilege set="required" name="proc_exec" />
+ <privilege set="required" name="proc_fork" />
+ <privilege set="required" name="sys_ip_config" ip-type="exclusive" />
+ <privilege set="required" name="sys_mount" />
+</brand>
diff --git a/usr/src/lib/brand/lx/zone/lx_boot.ksh b/usr/src/lib/brand/lx/zone/lx_boot.ksh
new file mode 100644
index 0000000000..9f4746e20a
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_boot.ksh
@@ -0,0 +1,92 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015, Joyent, Inc.
+#
+# lx boot script.
+#
+# The arguments to this script are the zone name and the zonepath.
+#
+
+. /usr/lib/brand/shared/common.ksh
+
+ZONENAME=$1
+ZONEPATH=$2
+ZONEROOT=$ZONEPATH/root
+
+w_missing=$(gettext "Warning: \"%s\" is not installed in the global zone")
+
+arch=`uname -p`
+if [ "$arch" = "i386" ]; then
+ ARCH32=i86
+ ARCH64=amd64
+else
+ echo "Unsupported architecture: $arch"
+ exit 2
+fi
+
+#
+# Run the lx_support boot hook.
+#
+/usr/lib/brand/lx/lx_support boot $ZONEPATH $ZONENAME
+if (( $? != 0 )) ; then
+ exit 1
+fi
+
+BRANDDIR=/native/usr/lib/brand/lx;
+EXIT_CODE=1
+
+#
+# Before we boot we validate and fix, if necessary, the required files within
+# the zone. These modifications can be lost if a patch or upgrade is applied
+# within the zone, so we validate and fix the zone every time it boots.
+#
+
+#
+# Determine the distro.
+#
+distro=""
+if [[ $(zonecfg -z $ZONENAME info attr name=docker) =~ "value: true" ]]; then
+ distro="docker"
+elif [[ -f $ZONEROOT/etc/redhat-release ]]; then
+ distro="redhat"
+elif [[ -f $ZONEROOT/etc/lsb-release ]]; then
+ if egrep -s Ubuntu $ZONEROOT/etc/lsb-release; then
+ distro="ubuntu"
+ elif [[ -f $ZONEROOT/etc/debian_version ]]; then
+ distro="debian"
+ fi
+elif [[ -f $ZONEROOT/etc/debian_version ]]; then
+ distro="debian"
+elif [[ -f $ZONEROOT/etc/alpine-release ]]; then
+ distro="busybox"
+fi
+
+[[ -z $distro ]] && fatal "Unsupported distribution!"
+
+#
+# Perform distro-specific customization.
+#
+. $(dirname $0)/lx_boot_zone_${distro}
+
+exit 0
diff --git a/usr/src/lib/brand/lx/zone/lx_boot_zone_busybox.ksh b/usr/src/lib/brand/lx/zone/lx_boot_zone_busybox.ksh
new file mode 100644
index 0000000000..1ad83902bc
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_boot_zone_busybox.ksh
@@ -0,0 +1,168 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# Customisation for busybox-init-based distributions. Assumes to have been
+# sourced from lx_boot.
+#
+
+tmpfile=/tmp/lx-busybox.$$
+
+# Check that the directories we're writing to aren't symlinks outside the zone
+safe_dir /etc
+safe_dir /etc/init.d
+
+# Generate network setup script
+#
+cat > $tmpfile <<EOF
+#!/sbin/runscript
+depend() {
+ need localmount
+ after bootmisc hwdrivers modules
+ provide net
+ keyword nojail noprefix novserver
+}
+start() {
+ if [ ! -e /etc/resolv.conf ]; then
+ echo "# AUTOMATIC ZONE CONFIG" > /etc/resolv.conf
+EOF
+zonecfg -z $ZONENAME info attr name=resolvers |
+awk '
+ {
+ if ($1 == "value:") {
+ nres = split($2, resolvers, ",")
+ }
+ }
+ END {
+ for (i = 1; i <= nres; i++) {
+ printf(" echo \"nameserver %s\" >> %s\n", resolvers[i],
+ "/etc/resolv.conf")
+ }
+ }
+' >> $tmpfile
+zonecfg -z $ZONENAME info attr name=dns-domain |
+awk '
+ {
+ if ($1 == "value:") {
+ dom = $2
+ }
+ }
+ END {
+ printf(" echo \"search %s\" >> %s\n", dom, "/etc/resolv.conf")
+ }
+' >> $tmpfile
+cat >> $tmpfile <<EOF
+ fi
+ return 0
+}
+stop() {
+ return 0
+}
+EOF
+fnm=$ZONEROOT/etc/init.d/networking
+if [[ -f $fnm || -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 755 $fnm
+fi
+
+
+#
+# The default /etc/inittab might spawn mingetty on each of the virtual consoles
+# as well as xdm on the X console. Since we don't have virtual consoles nor
+# an X console, spawn a single mingetty on /dev/console instead.
+#
+# Don't bother changing the file if it looks like we already did.
+#
+fnm=$ZONEROOT/etc/inittab
+if ! egrep -s "Modified by lx brand" $fnm; then
+ sed 's/^tty[1-6]:/# Disabled by lx brand: &/' \
+ $fnm > $tmpfile
+ echo "console::respawn:/sbin/getty 38400 console" >> $tmpfile
+ echo "# Modified by lx brand" >> $tmpfile
+
+ if [[ ! -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 644 $fnm
+ fi
+fi
+
+#
+# The following scripts attempt to start services or otherwise configure the
+# system in ways incompatible with zones, so replace them with stubs.
+#
+
+fnm=$ZONEROOT/etc/init.d/fsck
+[[ ! -h $fnm && -f $fnm ]] && cat <<DONE > $fnm
+#!/sbin/runscript
+
+depend() {
+ use dev clock modules
+}
+
+start() {
+ return 0
+}
+DONE
+
+fnm=$ZONEROOT/etc/init.d/hwclock
+[[ ! -h $fnm && -f $fnm ]] && cat <<DONE > $fnm
+#!/sbin/runscript
+
+depend() {
+ provide clock
+}
+
+start() {
+ return 0
+}
+DONE
+
+fnm=$ZONEROOT/etc/init.d/klogd
+[[ ! -h $fnm && -f $fnm ]] && cat <<DONE > $fnm
+#!/sbin/runscript
+
+depend() {
+ need clock hostname localmount
+ before net
+}
+
+start() {
+ return 0
+}
+DONE
+
+fnm=$ZONEROOT/etc/init.d/sysfs
+[[ ! -h $fnm && -f $fnm ]] && cat <<DONE > $fnm
+#!/sbin/runscript
+
+depend() {
+}
+
+start() {
+ return 0
+}
+DONE
+
+#
+# Setup for the /dev/shm mount.
+#
+fnm=$ZONEROOT/etc/fstab
+entry=$(awk '{if ($2 == "/dev/shm") print $2}' $fnm)
+if [[ -z "$entry" && ! -h $fnm ]]; then
+ echo "swapfs /dev/shm tmpfs defaults 0 0" >> $fnm
+fi
+
+# Hand control back to lx_boot
diff --git a/usr/src/lib/brand/lx/zone/lx_boot_zone_debian.ksh b/usr/src/lib/brand/lx/zone/lx_boot_zone_debian.ksh
new file mode 100644
index 0000000000..35ae59c19c
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_boot_zone_debian.ksh
@@ -0,0 +1,172 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# Customisation for Debian-based distributions. Assumes to have been
+# sourced from lx_boot.
+#
+
+tmpfile=/tmp/lx-debian.$$
+
+
+# Check that the directories we're writing to aren't symlinks outside the zone
+safe_dir /etc
+safe_dir /etc/init.d
+safe_dir /etc/network
+safe_dir /etc/rc0.d
+safe_dir /etc/rc1.d
+safe_dir /etc/rc2.d
+safe_dir /etc/rc3.d
+safe_dir /etc/rc4.d
+safe_dir /etc/rc5.d
+safe_dir /etc/rc6.d
+safe_dir /etc/rcS.d
+safe_opt_dir /etc/selinux
+
+# Populate resolve.conf setup files
+zonecfg -z $ZONENAME info attr name=resolvers | awk '
+BEGIN {
+ print("# AUTOMATIC ZONE CONFIG")
+}
+$1 == "value:" {
+ nres = split($2, resolvers, ",");
+ for (i = 1; i <= nres; i++) {
+ print("nameserver", resolvers[i]);
+ }
+}
+' > $tmpfile
+zonecfg -z $ZONENAME info attr name=dns-domain | awk '
+$1 == "value:" {
+ dom = $2
+}
+END {
+ print("search", dom);
+}
+' >> $tmpfile
+fnm=$ZONEROOT/etc/resolv.conf
+if [[ -f $fnm || -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+fi
+
+# Override network configuration
+zonecfg -z $ZONENAME info net | awk '
+BEGIN {
+ print("# AUTOMATIC ZONE CONFIG")
+ print("iface lo inet manual");
+}
+$1 == "physical:" {
+ print("iface", $2, "inet manual");
+}
+' > $tmpfile
+fnm=$ZONEROOT/etc/network/interfaces
+if [[ -f $fnm || -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+fi
+
+#
+# The default /etc/inittab might spawn mingetty on each of the virtual consoles
+# as well as xdm on the X console. Since we don't have virtual consoles nor
+# an X console, spawn a single mingetty on /dev/console instead.
+#
+# Don't bother changing the file if it looks like we already did.
+#
+fnm=$ZONEROOT/etc/inittab
+if ! egrep -s "Modified by lx brand" $fnm; then
+ sed 's/^[1-6]:/# Disabled by lx brand: &/' \
+ $fnm > $tmpfile
+ echo "1:2345:respawn:/sbin/getty 38400 console" >> $tmpfile
+ echo "# Modified by lx brand" >> $tmpfile
+
+ if [[ ! -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 644 $fnm
+ fi
+fi
+
+# The Debian init uses a combination of traditional rc-style service
+# definitions and upstart-style definitions.
+
+#
+# The following rc-style scripts attempt to start services or otherwise
+# configure the system in ways incompatible with zones, so don't execute them
+# at boot time.
+#
+unsupported_rc_services="
+ checkfs.sh
+ checkroot.sh
+ hwclock.sh
+ kmod
+ mtab.sh
+ procps
+ udev
+ udev-mtab
+"
+
+for file in $unsupported_rc_services; do
+ rm -f $ZONEROOT/etc/init.d/$file
+
+ rc_files="$(echo $ZONEROOT/etc/rc[0-6S].d/[SK]+([0-9])$file)"
+
+ if [[ "$rc_files" != \
+ "$ZONEROOT/etc/rc[0-6S].d/[SK]+([0-9])$file" ]]; then
+ for file in $rc_files; do
+ rm -f "$file"
+ done
+ fi
+done
+
+disable_svc()
+{
+ fnm=$ZONEROOT/etc/init/$1.override
+ [[ -h $fnm || -f $fnm ]] && return
+ echo "manual" > $fnm
+}
+
+
+#
+# Now customize upstart
+#
+
+RMSVCS="
+ network-interface-security
+ udev
+ udevmonitor
+ udevtrigger
+ udev-fallback-graphics
+ udev-finish
+"
+for f in $RMSVCS
+do
+ disable_svc $f
+done
+
+#
+# We need to setup for the /dev/shm mount. Unlike some other distros, Debian
+# can handle it as either /dev/shm or /run/shm. For simplicity we create an
+# fstab entry to force it into the /dev/shm style.
+#
+fnm=$ZONEROOT/etc/fstab
+entry=$(awk '{if ($2 == "/dev/shm") print $2}' $fnm)
+if [[ -z "$entry" && ! -h $fnm ]]; then
+ echo "swapfs /dev/shm tmpfs defaults 0 0" >> $fnm
+fi
+
+#
+# upstart modifications are complete
+#
+rm -f $tmpfile
+
+# Hand control back to lx_boot
diff --git a/usr/src/lib/brand/lx/zone/lx_boot_zone_redhat.ksh b/usr/src/lib/brand/lx/zone/lx_boot_zone_redhat.ksh
new file mode 100644
index 0000000000..566b401c18
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_boot_zone_redhat.ksh
@@ -0,0 +1,361 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+# Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
+#
+
+#
+# Since CentOS, Red Hat Enterprise Linux, and Fedora all use approximately
+# the same source, this file should be good for all three.
+#
+# Currently, this file assumed a pre-systemd existence, so this should be
+# CentOS 6.x or earlier. Testing has been done on CentOS 6.6.
+#
+
+tmpfile=/tmp/lx-redhat.$$
+
+
+# Before doing anything else, make sure some Centos-specific dirs are safe.
+# /etc/init.d is normally a symlink so we can't easily tell if it's safe so
+# check rc.d/init.d instead.
+
+safe_dir /etc/sysconfig
+safe_dir /etc/rc.d
+safe_dir /etc/rc.d/init.d
+safe_dir /etc/rc.d/rc0.d
+safe_dir /etc/rc.d/rc1.d
+safe_dir /etc/rc.d/rc2.d
+safe_dir /etc/rc.d/rc3.d
+safe_dir /etc/rc.d/rc4.d
+safe_dir /etc/rc.d/rc5.d
+safe_dir /etc/rc.d/rc6.d
+safe_opt_dir /etc/selinux
+
+# Generate the /etc/rc.d/init.d/network rc script
+cat > $tmpfile <<EOF
+#!/bin/bash
+# network Bring up/down networking
+#
+### BEGIN INIT INFO
+# Provides: \$network
+# Short-Description: Bring up/down networking
+# Description: Bring up/down networking
+### END INIT INFO
+
+case "\$1" in
+ start)
+ [ "\$EUID" != "0" ] && exit 4
+
+ if [ ! -e /etc/resolv.conf ]; then
+ if [ -h /etc/resolv.conf ]; then
+ rm -f /etc/resolv.conf
+ fi
+ echo "# AUTOMATIC ZONE CONFIG" > /etc/resolv.conf
+EOF
+zonecfg -z $ZONENAME info attr name=resolvers |
+awk '
+ {
+ if ($1 == "value:") {
+ nres = split($2, resolvers, ",")
+ }
+ }
+ END {
+ for (i = 1; i <= nres; i++) {
+ printf(" echo \"nameserver %s\" >> %s\n", resolvers[i],
+ "/etc/resolv.conf")
+ }
+ }
+' >> $tmpfile
+zonecfg -z $ZONENAME info attr name=dns-domain |
+awk '
+ {
+ if ($1 == "value:") {
+ dom = $2
+ }
+ }
+ END {
+ printf(" echo \"search %s\" >> %s\n", dom, "/etc/resolv.conf")
+ }
+' >> $tmpfile
+cat >> $tmpfile <<EOF
+ fi
+ touch /var/lock/subsys/network
+ rc=0
+ ;;
+ stop)
+ [ "\$EUID" != "0" ] && exit 4
+
+ rm -f /var/lock/subsys/network
+ rc=0
+ ;;
+ status)
+ echo "Configured devices:"
+ echo "lo \$(cd /dev/net; ls)"
+ echo "Currently active devices:"
+ echo \$(/sbin/ip -o link show up | awk -F ": " '{ print \$2 }')
+ rc=0
+ ;;
+ restart|reload|force-reload)
+ cd "\$CWD"
+ \$0 stop
+ \$0 start
+ rc=\$?
+ ;;
+ *)
+ echo "Usage: \$0 {start|stop|status|restart|reload|force-reload}"
+ exit 2
+esac
+
+exit \$rc
+EOF
+fnm=$ZONEROOT/etc/rc.d/init.d/network
+if [[ -f $fnm || -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 755 $fnm
+fi
+
+# This is specific to a systemd-based image
+sysdir=$ZONEROOT/etc/systemd/system
+if [[ -d $ZONEROOT/etc && ! -h $ZONEROOT/etc && -d $ZONEROOT/etc/systemd &&
+ ! -h $ZONEROOT/etc/systemd && -d $sysdir && ! -h $sysdir ]]; then
+ # don't use NetworkManager
+ rm -f $sysdir/dbus-org.freedesktop.nm-dispatcher.service
+ rm -f $sysdir/multi-user.target.wants/NetworkManager.service
+ rm -f $sysdir/dbus-org.freedesktop.NetworkManager.service
+ # our network setup needs to run
+ fnm=$sysdir/multi-user.target.wants/network.service
+ if [[ ! -f $fnm ]]; then
+ ln -s /etc/rc.d/init.d/network \
+ $sysdir/multi-user.target.wants/network.service
+ fi
+fi
+
+#
+# The default /etc/inittab only sets the runlevel. Make sure it's runlevel 3
+# and not runlevel 5 (X11).
+# Don't bother changing the file if it looks like we already did.
+#
+fnm=$ZONEROOT/etc/inittab
+if ! egrep -s "Modified by lx brand" $fnm; then
+ sed 's/^id:5:initdefault:/id:3:initdefault: &/' \
+ $fnm > $tmpfile
+ echo "# Modified by lx brand" >> $tmpfile
+
+ if [[ ! -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 644 $fnm
+ fi
+fi
+
+#
+# Ensure svcs depending on $network will start.
+#
+fnm=$ZONEROOT/etc/sysconfig/network
+if ! egrep -s "NETWORKING=yes" $fnm; then
+ cfghnm=$(zonecfg -z $ZONENAME info attr name=hostname | \
+ awk '{if ($1 == "value:") print $2}')
+ if [[ -z "$cfghnm" ]]; then
+ cfghnm=$ZONENAME
+ fi
+ if [[ ! -h $fnm ]]; then
+ cat > $fnm <<- EOF
+ NETWORKING=yes
+ HOSTNAME=$cfghnm
+ EOF
+ fi
+fi
+
+#
+# SELinux must be disabled otherwise we won't get past init.
+#
+fnm=$ZONEROOT/etc/selinux/config
+if egrep -s "^SELINUX=enforcing|^SELINUX=permissive" $fnm; then
+ tmpfile=/tmp/selinux_config.$$
+
+ sed 's/^SELINUX=.*$/SELINUX=disabled/' $fnm > $tmpfile
+ if [[ ! -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 644 $fnm
+ fi
+fi
+
+#
+# /etc/rc.d/init.d/keytable tries to load a physical keyboard map, which won't
+# work in a zone. If we remove etc/sysconfig/keyboard, it won't try this at all.
+#
+fnm=$ZONEROOT/etc/sysconfig/keyboard
+if [[ ! -h $fnm ]]; then
+ rm -f $ZONEROOT/etc/sysconfig/keyboard
+fi
+
+# The Centos init uses a combination of traditional rc-style service
+# definitions and upstart-style definitions.
+
+#
+# The following rc-style scripts attempt to start services or otherwise
+# configure the system in ways incompatible with zones, so don't execute them
+# at boot time.
+#
+unsupported_rc_services="
+ acpid
+ auditd
+ gpm
+ hpoj
+ ip6tables
+ iptables
+ irda
+ irqbalance
+ iscsi
+ isdn
+ kdump
+ kudzu
+ mdmpd
+ mdmonitor
+ microcode_ctl
+ netdump
+ ntpd
+ ntpdate
+ pcmcia
+ psacct
+ quota_nld
+ random
+ rawdevices
+ smartd
+"
+
+for file in $unsupported_rc_services; do
+ rm -f $ZONEROOT/etc/rc.d/init.d/$file
+
+ rc_files="$(echo $ZONEROOT/etc/rc.d/rc[0-6].d/[SK]+([0-9])$file)"
+
+ if [[ "$rc_files" != \
+ "$ZONEROOT/etc/rc.d/rc[0-6].d/[SK]+([0-9])$file" ]]; then
+ for file in $rc_files; do
+ rm -f "$file"
+ done
+ fi
+done
+
+disable_svc()
+{
+ # XXX - TBD does this work like on Ubuntu?
+ #
+ fnm=$ZONEROOT/etc/init/$1.override
+ [[ -h $fnm || -f $fnm ]] && return
+ echo "manual" > $fnm
+
+ # fnm=$ZONEROOT/etc/init/$1.conf
+ # rm -f $fnm
+}
+
+RMSVCS="control-alt-delete
+ ttyS0"
+
+#
+# Now customize upstart services
+#
+
+for f in $RMSVCS
+do
+ disable_svc $f
+done
+
+if [[ ! -f $ZONEROOT/etc/init/tty.override ]]; then
+ cat > $ZONEROOT/etc/init/tty.override <<- EOF
+ # tty - getty
+ #
+ # This service maintains a getty on the console.
+
+ stop on runlevel [S016]
+
+ respawn
+ instance console
+ exec /sbin/mingetty console
+ EOF
+fi
+
+if [[ ! -f $ZONEROOT/etc/init/start-ttys.override ]]; then
+ cat > $ZONEROOT/etc/init/start-ttys.override <<- EOF
+ # This service starts the configured number of gettys.
+ #
+
+ start on stopped rc RUNLEVEL=[2345]
+
+ task
+ script
+ initctl start tty
+ end script
+ EOF
+fi
+
+#
+# There is a lot of stuff in the standard halt and reboot scripts that we
+# have no business running in a zone. Fortunately, the stuff we want to
+# skip is all in one contiguous chunk.
+#
+# Don't bother to modify the file if it looks like we already did.
+#
+fnm=$ZONEROOT/etc/rc.d/init.d/halt
+if ! egrep -s "Disabled by lx brand" $fnm; then
+ awk 'BEGIN {skip = ""}
+ /^# Save mixer/ {skip = "# Disabled by lx brand: "}
+ /halt.local/ {skip = ""}
+ /./ {print skip $0}' $fnm > /tmp/halt.$$
+
+ if [[ $? -eq 0 && ! -h $fnm ]]; then
+ mv -f /tmp/halt.$$ $fnm
+ chmod 755 $fnm
+ fi
+fi
+
+#
+# Fix up /etc/rc.d/rc.sysinit:
+#
+# 1) /sbin/hwclock requires the iopl() system call, which BrandZ won't support.
+# Since the hardware clock cannot be set from within a zone, we comment out
+# the line.
+#
+# 2) Disable dmesg commands, since we don't implement klogctl
+#
+# 3) Disable initlog and the mount of /dev/pts
+#
+# 4) Don't touch /dev/tty* in order to start virtual terminals, as that won't
+# work from within a zone.
+#
+# 5) Don't try to check the root filesystem (/) as there is no associated
+# physical device, and any attempt to run fsck will fail.
+#
+fnm=$ZONEROOT/etc/rc.d/rc.sysinit
+tmpfile=/tmp/lx_rc.sysinit.$$
+
+sed 's@^/sbin/hwclock@# lx: &@
+ s@^/bin/dmesg -n@# lx: &@
+ s@^dmesg -s@# lx: &@
+ s@^initlog -c \"fsck@# lx: &@
+ s@^mount -n -o remount /dev/shm @mount -t tmpfs tmpfs /dev/shm @
+ s@^mount .* /dev/pts@# lx: &@
+ /^#remount \/dev\/shm/d' \
+ $fnm > $tmpfile
+
+if [[ ! -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+ chmod 755 $fnm
+fi
+
+#
+# sysinit modifications are complete
+#
+rm -f $tmpfile
+
+# Hand control back to lx_boot
diff --git a/usr/src/lib/brand/lx/zone/lx_boot_zone_ubuntu.ksh b/usr/src/lib/brand/lx/zone/lx_boot_zone_ubuntu.ksh
new file mode 100644
index 0000000000..27d047e4ca
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_boot_zone_ubuntu.ksh
@@ -0,0 +1,139 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+#
+# Customisation for Ubuntu-based distributions. Assumes to have been
+# sourced from lx_boot.
+#
+tmpfile=/tmp/lx-ubuntu.$$
+
+# Check that the directories we're writing to aren't symlinks outside the zone
+safe_dir /etc
+safe_dir /etc/init
+safe_dir /etc/resolvconf
+safe_dir /etc/resolvconf/resolv.conf.d
+safe_dir /etc/network
+safe_dir /etc/network/interfaces.d
+safe_dir /etc/network/interfaces.d/smartos
+
+# Populate resolve.conf setup files
+zonecfg -z $ZONENAME info attr name=resolvers | awk '
+BEGIN {
+ print("# AUTOMATIC ZONE CONFIG")
+}
+$1 == "value:" {
+ nres = split($2, resolvers, ",");
+ for (i = 1; i <= nres; i++) {
+ print("nameserver", resolvers[i]);
+ }
+}
+' > $tmpfile
+zonecfg -z $ZONENAME info attr name=dns-domain | awk '
+$1 == "value:" {
+ dom = $2
+}
+END {
+ print("search", dom);
+}
+' >> $tmpfile
+fnm=$ZONEROOT/etc/resolvconf/resolv.conf.d/tail
+if [[ -f $fnm || -h $fnm || ! -e $fnm ]]; then
+ mv -f $tmpfile $fnm
+fi
+
+# Override network configuration
+zonecfg -z $ZONENAME info net | awk '
+BEGIN {
+ print("# AUTOMATIC ZONE CONFIG")
+}
+$1 == "physical:" {
+ print("iface", $2, "inet manual");
+}
+' > $tmpfile
+fnm=$ZONEROOT/etc/network/interfaces.d/smartos
+if [[ -f $fnm || -h $fnm ]]; then
+ mv -f $tmpfile $fnm
+fi
+
+src_fnm=$ZONEROOT/etc/init/console.conf
+tgt_fnm=$ZONEROOT/etc/init/console.override
+if [[ -f $src_fnm && ! -f $tgt_fnm && ! -h $tgt_fnm ]] then
+ sed -e 's/lxc/smartos/' $src_fnm > /tmp/console.conf.$$
+ mv /tmp/console.conf.$$ $tgt_fnm
+fi
+
+fnm=$ZONEROOT/etc/init/container-detect.override
+if [[ ! -f $fnm && ! -h $fnm ]] then
+ cat <<'DONE' > $fnm
+description "Track if upstart is running in a container"
+
+start on mounted MOUNTPOINT=/run
+
+env container
+env LIBVIRT_LXC_UUID
+
+emits container
+
+pre-start script
+ container=smartos
+ echo "$container" > /run/container_type || true
+ initctl emit --no-wait container CONTAINER=$container
+ exit 0
+end script
+DONE
+fi
+
+# XXX need to add real mounting into this svc definition
+
+fnm=$ZONEROOT/etc/init/mountall.override
+if [[ ! -h $fnm ]] then
+ cat <<DONE > $fnm
+description "Mount filesystems on boot"
+
+start on startup
+
+task
+
+emits virtual-filesystems
+emits local-filesystems
+emits remote-filesystems
+emits all-swaps
+emits filesystem
+emits mounted
+
+script
+ echo "/dev/zfsds0 / zfs rw 0 0" > /etc/mtab
+ echo "proc /proc proc rw,noexec,nosuid,nodev 0 0" >> /etc/mtab
+
+ /sbin/initctl emit --no-wait virtual-filesystems
+ /bin/mount -t tmpfs tmpfs /dev/shm || true
+ /bin/mount -t tmpfs tmpfs /run || true
+ /bin/mkdir -p /run/lock || true
+ /bin/ln -s /dev/shm /run/shm || true
+ /sbin/initctl emit --no-wait mounted MOUNTPOINT=/run TYPE=tmpfs
+ /sbin/initctl emit --no-wait local-filesystems
+ /sbin/initctl emit --no-wait all-swaps
+ /sbin/initctl emit --no-wait filesystem
+end script
+DONE
+fi
+
+#
+# upstart modifications are complete
+#
+rm -f $tmpfile
+
+# Hand control back to lx_boot
diff --git a/usr/src/lib/brand/lx/zone/lx_install.ksh b/usr/src/lib/brand/lx/zone/lx_install.ksh
new file mode 100644
index 0000000000..c31b8355ac
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/lx_install.ksh
@@ -0,0 +1,194 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# Copyright 2016 Joyent, Inc. All rights reserved.
+#
+
+#
+# This is only an example install script. It is not currently used for anything.
+#
+
+PATH=/bin:/usr/bin:/usr/sbin
+export PATH
+
+fullpath()
+{
+ typeset path="$1"
+
+ echo $path | egrep -s "^/" || path="${PWD:=$(pwd)}/$path"
+ echo $path
+}
+
+makedir()
+{
+ typeset dirname=$(fullpath "$1")
+ typeset mode=""
+
+ [[ $# -eq 2 ]] && mode="-m $2"
+
+ [[ -d "$dirname" ]] && return
+
+ if ! mkdir $mode -p "$dirname"; then
+ echo $(gettext "Aborting installation...")
+ exit 255
+ fi
+}
+
+symlink()
+{
+ typeset src="$1"
+ typeset dst=$(fullpath "$2")
+
+ [[ -e "$dst" || -h "$dst" ]] && rm -f "$dst"
+
+ if ! ln -s "$src" "$dst"; then
+ echo $(gettext "Aborting installation...")
+ exit 255
+ fi
+}
+
+install_ln()
+{
+ typeset source="$1"
+ typeset target=$(fullpath "$2")
+
+ log " Installing \"$target\""
+
+ mv -f "$target" "$target.$tag" 2>/dev/null
+
+ if ! ln -s "$source" "$target"; then
+ return 1
+ fi
+
+ return 0
+}
+
+# If we weren't passed 3 arguments, exit now.
+[[ $# -lt 3 ]] && exit 254
+
+# Extract the brand directory name from the path.
+branddir=$(dirname "$0")
+zonename="$1"
+zoneroot="$2"
+install_src="3"
+install_root="$zoneroot/root"
+ZPOOL=`df $ZONEROOT | awk -F '[()]' '{split($2, field, "/"); print field[1]; }'`
+if [ -z "$ZPOOL" ]; then
+ ROOTDEV="none"
+else
+ ROOTDEV="/dev/$ZPOOL"
+fi
+
+if [[ ! -f "$install_src" ]]; then
+ echo "$install_src: file not found\n"
+ exit 254
+fi
+
+if [[ ! -d "$install_root" ]]; then
+ if ! mkdir -p "$install_root" 2>/dev/null; then
+ echo "Could not create install directory $install_root"
+ exit 254
+ fi
+fi
+
+if ! ( cd "$install_root" && gtar -xzf "$install_src" ) ; then
+ echo "Error: extraction from tar archive failed"
+ exit 255
+fi
+
+tag="lxsave_$(date +%m.%d.%Y@%T)"
+
+if [[ ! -d "$install_root" ]]; then
+ exit 255
+fi
+
+cd "$install_root"
+
+makedir native/dev
+makedir native/etc/default
+makedir native/etc/svc/volatile
+makedir native/lib
+makedir native/proc
+makedir native/tmp 1777
+makedir native/usr
+makedir native/var
+
+makedir mnt
+makedir opt
+makedir usr/local/bin
+makedir usr/local/include
+makedir usr/local/lib
+makedir usr/local/sbin
+makedir usr/local/share
+makedir usr/local/src
+
+makedir dev 0755
+makedir tmp 1777
+makedir proc 0555
+makedir boot 0755
+
+symlink /bin/sh sbin/sh
+symlink /bin/su usr/bin/su
+symlink /native/usr/lib/ld.so.1 usr/lib/ld.so.1
+
+libpam_so="$(echo lib/libpam.so.0.*)"
+libpam_misc="$(echo lib/libpam_misc.so.0.*)"
+libpamc_so="$(echo lib/libpamc.so.0.*)"
+
+symlink "/$libpam_so" lib/libpam.so.0
+symlink "/$libpam_misc" lib/libpam_misc.so.0
+symlink "/$libpamc_so" lib/libpamc.so.0
+
+makedir var/ld
+
+if ! crle -c var/ld/ld.config -l /native/lib:/native/usr/lib \
+ -s /native/lib/secure:/native/usr/lib/secure; then
+ exit 255
+fi
+
+mv -f etc/fstab etc/fstab.$tag 2>/dev/null
+
+cat > etc/fstab <<- EOF
+ $ROOTDEV / zfs defaults 1 1
+ proc /proc proc defaults 0 0
+EOF
+
+if [[ $? -ne 0 ]]; then
+ exit 255
+fi
+
+if [[ ! -e "$install_root/etc/hosts" ]]; then
+ cat > "$install_root/etc/hosts" <<-_EOF_
+ 127.0.0.1 localhost
+ _EOF_
+fi
+
+#
+# Perform distribution-specific changes.
+#
+distro=""
+if [[ -f etc/redhat-release ]]; then
+ distro="redhat"
+elif [[ -f etc/lsb-release ]]; then
+ if egrep -s Ubuntu etc/lsb-release; then
+ distro="ubuntu"
+ elif [[ -f etc/debian_version ]]; then
+ distro="debian"
+ fi
+elif [[ -f etc/debian_version ]]; then
+ distro="debian"
+fi
+
+if [[ -z $distro ]]; then
+ exit 255
+fi
+
+exit 0
diff --git a/usr/src/lib/brand/lx/zone/platform.xml b/usr/src/lib/brand/lx/zone/platform.xml
new file mode 100644
index 0000000000..060343e38f
--- /dev/null
+++ b/usr/src/lib/brand/lx/zone/platform.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0"?>
+
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+ Copyright 2017 Joyent, Inc.
+
+ DO NOT EDIT THIS FILE.
+-->
+
+<!DOCTYPE platform PUBLIC "-//Sun Microsystems Inc//Zones Platform//EN"
+ "file:///usr/share/lib/xml/dtd/zone_platform.dtd.1">
+
+<platform name="lx" allow-exclusive-ip="true">
+ <!-- Global filesystems to mount when booting the zone -->
+ <global_mount special="/dev" directory="/native/dev" type="dev"
+ opt="attrdir=%R/dev" />
+
+ <!--
+ Local filesystems to mount when booting the zone. The /native/sbin
+ entry is needed so that we can replace ifconfig with its native
+ counterpart (this is required for exclusive-stack zones to work).
+ We also need dladm from /native/sbin.
+ -->
+ <global_mount special="/lib" directory="/native/lib"
+ opt="ro" type="lofs" />
+ <global_mount special="/usr" directory="/native/usr"
+ opt="ro" type="lofs" />
+ <global_mount special="/usr/lib/brand/lx/etc_default_nfs"
+ directory="/native/etc/default/nfs" type="lofs" opt="ro" />
+ <global_mount special="/etc/default/dhcpagent"
+ directory="/native/etc/default/dhcpagent" type="lofs" opt="ro" />
+ <global_mount special="/etc/netconfig"
+ directory="/native/etc/netconfig" type="lofs" opt="ro" />
+ <global_mount special="/etc/nfssec.conf"
+ directory="/native/etc/nfssec.conf" type="lofs" opt="ro" />
+ <global_mount special="/sbin"
+ directory="/native/sbin" opt="ro,nodevices" type="lofs" />
+ <global_mount special="/usr/lib/brand/lx/ld" directory="/var/ld"
+ opt="ro" type="lofs" />
+ <global_mount special="/etc/zones/%z.xml"
+ directory="/native/etc/zones/%z.xml" opt="ro" type="lofs" />
+ <global_mount special="/var/zonecontrol/%z" directory="/native/.zonecontrol"
+ opt="ro,nodevices,nosetuid,noexec" type="lofs" />
+
+ <!-- Local filesystems to mount when booting the zone -->
+ <mount special="/native/dev" directory="/dev" type="lx_devfs" />
+ <mount special="proc" directory="/native/proc" type="proc" />
+ <mount special="swap" directory="/native/etc/svc/volatile"
+ type="tmpfs" />
+ <mount special="swap" directory="/native/tmp" type="tmpfs" />
+ <mount special="objfs" directory="/system/object" type="objfs" />
+ <mount special="ctfs" directory="/system/contract" type="ctfs" />
+ <mount special="mnttab" directory="/etc/mnttab" type="mntfs" />
+ <mount special="lxproc" directory="/proc" type="lx_proc" />
+
+ <!-- Devices to create under /dev -->
+ <device match="arp" />
+ <device match="dtrace/*" />
+ <device match="dtrace/provider/*" />
+ <device match="eventfd" />
+ <device match="full" />
+ <device match="inotify" />
+ <device match="ipnet" />
+ <device match="kstat" />
+ <device match="lo0" />
+ <device match="null" />
+ <device match="poll" />
+ <device match="pts/*" />
+ <device match="random" />
+ <device match="signalfd" />
+ <device match="tcp" />
+ <device match="tcp6" />
+ <device match="ticotsord" />
+ <device match="timerfd" />
+ <device match="tty" />
+ <device match="udp" />
+ <device match="udp6" />
+ <device match="urandom" />
+ <device match="zero" />
+ <device match="zfs" />
+ <device match="zvol/dsk/%P/%z/*" />
+ <device match="zvol/rdsk/%P/%z/*" />
+
+ <!-- Devices to create in exclusive IP zone only -->
+ <device match="dld" ip-type="exclusive" />
+ <device match="icmp" ip-type="exclusive" />
+ <device match="icmp6" ip-type="exclusive" />
+ <device match="ip" ip-type="exclusive" />
+ <device match="ip6" ip-type="exclusive" />
+ <device match="ipauth" ip-type="exclusive" />
+ <device match="ipf" ip-type="exclusive" />
+ <device match="ipl" ip-type="exclusive" />
+ <device match="iplookup" ip-type="exclusive" />
+ <device match="ipmpstub" ip-type="exclusive" />
+ <device match="ipnat" ip-type="exclusive" />
+ <device match="ipscan" ip-type="exclusive" />
+ <device match="ipsecah" ip-type="exclusive" />
+ <device match="ipsecesp" ip-type="exclusive" />
+ <device match="ipstate" ip-type="exclusive" />
+ <device match="ipsync" ip-type="exclusive" />
+ <device match="keysock" ip-type="exclusive" />
+ <device match="net/*" ip-type="exclusive" />
+ <device match="rawip" ip-type="exclusive" />
+ <device match="rawip6" ip-type="exclusive" />
+ <device match="rts" ip-type="exclusive" />
+ <device match="sad/admin" ip-type="exclusive" />
+ <device match="sctp" ip-type="exclusive" />
+ <device match="sctp6" ip-type="exclusive" />
+ <device match="spdsock" ip-type="exclusive" />
+ <device match="sppp" ip-type="exclusive" />
+ <device match="sppptun" ip-type="exclusive" />
+ <device match="vni" ip-type="exclusive" />
+
+ <!-- Renamed devices to create under /dev -->
+ <device match="brand/lx/autofs" name="autofs" />
+ <device match="brand/lx/ptmx" name="ptmx" />
+ <device match="zcons/%z/zoneconsole" name="console" />
+ <device match="zfd/%z/slave/0" name="zfd/0" />
+ <device match="zfd/%z/slave/1" name="zfd/1" />
+ <device match="zfd/%z/slave/2" name="zfd/2" />
+ <device match="zfd/%z/slave/3" name="zfd/3" />
+ <device match="zfd/%z/slave/4" name="zfd/4" />
+
+ <!-- Audio devices to create under /dev -->
+ <device match="brand/lx/dsp" name="dsp" />
+ <device match="brand/lx/mixer" name="mixer" />
+
+ <!-- Symlinks to create under /dev -->
+ <symlink source="fd" target="../proc/self/fd" />
+ <symlink source="stderr" target="../proc/self/fd/2" />
+ <symlink source="stdin" target="../proc/self/fd/0" />
+ <symlink source="stdout" target="../proc/self/fd/1" />
+ <symlink source="systty" target="console" />
+ <symlink source="kmsg" target="console" />
+ <symlink source="conslog" target="console" />
+
+ <!-- Create a mount point for /dev/shm tmpfs (see shm_overview(7)) -->
+ <!-- We need to force a dir for the Linux mount to work ok -->
+ <symlink source="shm/loop" target="." />
+ <!-- Create a dummy /dev/xconsole -->
+ <device match="null" name="xconsole" />
+
+</platform>
diff --git a/usr/src/lib/brand/shared/zone/common.ksh b/usr/src/lib/brand/shared/zone/common.ksh
index 52441d814a..0f87686414 100644
--- a/usr/src/lib/brand/shared/zone/common.ksh
+++ b/usr/src/lib/brand/shared/zone/common.ksh
@@ -19,6 +19,7 @@
# CDDL HEADER END
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014, Joyent, Inc. All rights reserved.
#
#
@@ -96,9 +97,27 @@ vlog()
safe_dir()
{
typeset dir="$1"
+ typeset pwd_dir=""
- if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
- fatal "$e_baddir" "$dir"
+ if [[ -d $ZONEROOT/$dir ]]; then
+ if [[ -h $ZONEROOT/$dir ]]; then
+ #
+ # When dir is a symlink to a directory, we 'cd' to that
+ # directory to ensure that's under $ZONEROOT. We use pwd
+ # from /usr/bin instead of built-in because they give
+ # different results.
+ #
+ pwd_dir=$(cd $ZONEROOT/$dir && /usr/bin/pwd)
+ if [[ $pwd_dir =~ "^$ZONEROOT" ]]; then
+ return;
+ else
+ fatal \
+ "$e_baddir: symlink out of zoneroot" "$dir"
+ fi
+ else
+ # it's a dir and not a symlink, so that's ok.
+ return
+ fi
fi
}
@@ -109,9 +128,7 @@ safe_opt_dir()
[[ ! -e $ZONEROOT/$dir ]] && return
- if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
- fatal "$e_baddir" "$dir"
- fi
+ safe_dir $dir
}
# Only make a copy if we haven't already done so.
@@ -187,7 +204,7 @@ safe_replace()
fi
cat <<-END >$filename || exit 1
- #!/bin/sh -p
+ #!/bin/sh
#
# Solaris Brand Replacement
#
@@ -333,10 +350,12 @@ post_unpack()
#
# Check if the image was created with a valid libc.so.1.
#
- hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1`
- if (( $? != 0 )); then
- vlog "$f_hwcap_info" "$hwcap"
- fail_fatal "$f_sanity_hwcap"
+ if [[ -f $ZONEROOT/lib/libc.so.1 ]]; then
+ hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1`
+ if (( $? != 0 )); then
+ vlog "$f_hwcap_info" "$hwcap"
+ fail_fatal "$f_sanity_hwcap"
+ fi
fi
( cd "$ZONEROOT" && \
@@ -1003,41 +1022,36 @@ install_image()
return 0
}
-# Setup i18n output
-TEXTDOMAIN="SUNW_OST_OSCMD"
-export TEXTDOMAIN
-
-e_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
-e_baddir=$(gettext "Invalid '%s' directory within the zone")
-e_badfile=$(gettext "Invalid '%s' file within the zone")
-e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
-e_not_found=$(gettext "%s: error: file or directory not found.")
-e_install_abort=$(gettext "Installation aborted.")
-e_not_readable=$(gettext "Cannot read directory '%s'")
-e_not_dir=$(gettext "Error: must be a directory")
-e_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.")
-e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
-e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
-e_tmpfile=$(gettext "Unable to create temporary file")
-e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
-f_mkdir=$(gettext "Unable to create directory %s.")
-f_chmod=$(gettext "Unable to chmod directory %s.")
-f_chown=$(gettext "Unable to chown directory %s.")
-f_hwcap_info=$(gettext "HWCAP: %s\n")
-f_sanity_hwcap=$(gettext \
-"The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\
+e_cannot_wrap="%s: error: wrapper file already exists"
+e_baddir="Invalid '%s' directory within the zone"
+e_badfile="Invalid '%s' file within the zone"
+e_path_abs="Pathname specified to -a '%s' must be absolute."
+e_not_found="%s: error: file or directory not found."
+e_install_abort="Installation aborted."
+e_not_readable="Cannot read directory '%s'"
+e_not_dir="Error: must be a directory"
+e_unknown_archive="Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive."
+e_absolute_archive="Error: archive contains absolute paths instead of relative paths."
+e_mismatch_archive="Error: the archive top-level directory (%s) does not match the zonepath (%s)."
+e_tmpfile="Unable to create temporary file"
+e_root_full="Zonepath root %s exists and contains data; remove or move aside prior to install."
+f_mkdir="Unable to create directory %s."
+f_chmod="Unable to chmod directory %s."
+f_chown="Unable to chown directory %s."
+f_hwcap_info="HWCAP: %s\n"
+f_sanity_hwcap="The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\
" The zone will not boot on this platform. See the zone's\n"\
-" documentation for the recommended way to create the archive.")
+" documentation for the recommended way to create the archive."
-m_analyse_archive=$(gettext "Analysing the archive")
+m_analyse_archive="Analysing the archive"
-not_readable=$(gettext "Cannot read file '%s'")
-not_flar=$(gettext "Input is not a flash archive")
-bad_flar=$(gettext "Flash archive is a corrupt")
-bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
-f_unpack_failed=$(gettext "Unpacking the archive failed")
-unknown_archiver=$(gettext "Archiver %s is not supported")
-cmd_not_exec=$(gettext "Required command '%s' not executable!")
+not_readable="Cannot read file '%s'"
+not_flar="Input is not a flash archive"
+bad_flar="Flash archive is a corrupt"
+bad_zfs_flar="Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax."
+f_unpack_failed="Unpacking the archive failed"
+unknown_archiver="Archiver %s is not supported"
+cmd_not_exec="Required command '%s' not executable!"
#
# Exit values used by the script, as #defined in <sys/zone.h>
diff --git a/usr/src/lib/brand/shared/zone/uninstall.ksh b/usr/src/lib/brand/shared/zone/uninstall.ksh
index 468a7ed92f..923363c864 100644
--- a/usr/src/lib/brand/shared/zone/uninstall.ksh
+++ b/usr/src/lib/brand/shared/zone/uninstall.ksh
@@ -35,31 +35,31 @@ bname=`basename $0`
#
# error messages
#
-m_usage=$(gettext "Usage: %s: [-hFn]")
-
-m_1_zfs_promote=$(gettext "promoting '%s'.")
-m_1_zfs_destroy=$(gettext "destroying '%s'.")
-m_2_zfs_rename=$(gettext "renaming '%s' to '%s'.")
-m_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.")
-m_rm_r=$(gettext "recursively deleting '%s'.")
-m_rm=$(gettext "deleting '%s'.")
-
-w_no_ds=$(gettext "Warning: no zonepath dataset found.")
-
-f_usage_err=$(gettext "Error: invalid usage")
-f_abort=$(gettext "Error: internal error detected, aborting.")
-f_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.")
-f_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.")
-f_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.")
-f_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset.")
-f_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.")
-f_user_snap=$(gettext "Error: user snapshot(s) detected.")
-f_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.")
-f_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.")
-f_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.")
-f_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.")
-f_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.")
-f_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.")
+m_usage="Usage: %s: [-hFn]"
+
+m_1_zfs_promote="promoting '%s'."
+m_1_zfs_destroy="destroying '%s'."
+m_2_zfs_rename="renaming '%s' to '%s'."
+m_3_zfs_set="setting property %s='%s' for '%s'."
+m_rm_r="recursively deleting '%s'."
+m_rm="deleting '%s'."
+
+w_no_ds="Warning: no zonepath dataset found."
+
+f_usage_err="Error: invalid usage"
+f_abort="Error: internal error detected, aborting."
+f_1_zfs_promote="Error: promoting ZFS dataset '%s'."
+f_2_zfs_rename="Error: renaming ZFS dataset '%s' to '%s'."
+f_3_zfs_set="Error: setting ZFS propery %s='%s' for '%s'."
+f_1_zfs_destroy="Error: destroying ZFS dataset."
+f_2_zfs_get="Error: reading ZFS dataset property '%s' from '%s'."
+f_user_snap="Error: user snapshot(s) detected."
+f_stray_snap="Error: uncloned snapshot(s) detected."
+f_stray_clone="Error: cloned zone datasets found outsize of zone."
+f_rm_snap="Error: please delete snapshot(s) and retry uninstall."
+f_rm_clone="Error: please delete clone(s) and retry uninstall."
+f_iu_clone="Error: cloned zone dataset(s) in use."
+f_dis_clone="Error: please stop using clone(s) and retry uninstall."
#
# functions
diff --git a/usr/src/lib/common/i386/crtn.s b/usr/src/lib/common/i386/crtn.s
index 6e37e25a8f..413c102006 100644
--- a/usr/src/lib/common/i386/crtn.s
+++ b/usr/src/lib/common/i386/crtn.s
@@ -33,7 +33,6 @@
*
* For further details - see bug#4433015
*/
- .ident "%Z%%M% %I% %E% SMI"
.file "crtn.s"
/*
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index 59b9866285..df718d6490 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#include <stdio.h>
@@ -179,6 +180,7 @@ static const hcc_t hc_canon[] = {
{ PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
{ PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
{ PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
+ { PORT, TOPO_STABILITY_PRIVATE },
{ POWERBOARD, TOPO_STABILITY_PRIVATE },
{ POWERMODULE, TOPO_STABILITY_PRIVATE },
{ PSU, TOPO_STABILITY_PRIVATE },
@@ -194,6 +196,7 @@ static const hcc_t hc_canon[] = {
{ STRAND, TOPO_STABILITY_PRIVATE },
{ SUBCHASSIS, TOPO_STABILITY_PRIVATE },
{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
+ { TRANSCEIVER, TOPO_STABILITY_PRIVATE },
{ XAUI, TOPO_STABILITY_PRIVATE },
{ XFP, TOPO_STABILITY_PRIVATE }
};
@@ -799,7 +802,7 @@ make_hc_pairs(topo_mod_t *mod, char *fmri, int *num)
int
make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part,
-char **rev, nvlist_t **auth)
+ char **rev, nvlist_t **auth)
{
char *starti, *startn, *endi, *copy;
char *aname = NULL, *aid = NULL, *fs;
diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
index 3ea35cdddd..e0adb6e0ab 100644
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
@@ -22,6 +22,9 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
#ifndef _LIBTOPO_H
#define _LIBTOPO_H
@@ -389,6 +392,8 @@ extern void topo_hdl_free(topo_hdl_t *, void *, size_t);
extern int topo_hdl_nvalloc(topo_hdl_t *, nvlist_t **, uint_t);
extern int topo_hdl_nvdup(topo_hdl_t *, nvlist_t *, nvlist_t **);
extern char *topo_hdl_strdup(topo_hdl_t *, const char *);
+extern char *topo_hdl_strsplit(topo_hdl_t *, const char *, const char *,
+ char **);
/*
* Interfaces for converting sensor/indicator types, units, states, etc to
diff --git a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
index b81f4fd7c6..c6ff800951 100644
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
@@ -76,6 +76,7 @@ SYMBOL_VERSION SUNWprivate {
topo_hdl_prominfo;
topo_hdl_strdup;
topo_hdl_strfree;
+ topo_hdl_strsplit;
topo_hdl_zalloc;
topo_led_state_name;
topo_led_type_name;
@@ -118,6 +119,7 @@ SYMBOL_VERSION SUNWprivate {
topo_mod_str2nvl;
topo_mod_strdup;
topo_mod_strfree;
+ topo_mod_strsplit;
topo_mod_unload;
topo_mod_unregister;
topo_mod_walk_init;
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 7b29adad69..9de7a86736 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#ifndef _TOPO_HC_H
@@ -76,6 +76,7 @@ extern "C" {
#define PCIEX_ROOT "pciexrc"
#define PCIEX_SWUP "pciexswu"
#define PCIEX_SWDWN "pciexswd"
+#define PORT "port"
#define POWERBOARD "powerboard"
#define POWERMODULE "powermodule"
#define PSU "psu"
@@ -90,6 +91,7 @@ extern "C" {
#define SP "sp"
#define SUBCHASSIS "subchassis"
#define SYSTEMBOARD "systemboard"
+#define TRANSCEIVER "transceiver"
#define XAUI "xaui"
#define XFP "xfp"
@@ -161,6 +163,20 @@ extern "C" {
#define TOPO_PROP_SAS_PHY_MASK "phy-mask"
#define TOPO_PROP_SAS_CONNECTOR_TYPE "sas-connector-type"
+#define TOPO_PGROUP_PORT "port"
+#define TOPO_PROP_PORT_TYPE "type"
+#define TOPO_PROP_PORT_TYPE_SFF "sff"
+
+#define TOPO_PGROUP_TRANSCEIVER "transceiver"
+#define TOPO_PROP_TRANSCEIVER_TYPE "type"
+#define TOPO_PROP_TRANSCEIVER_USABLE "usable"
+
+#define TOPO_PGROUP_SFF_TRANSCEIVER "sff-transceiver"
+#define TOPO_PORT_SFF_TRANSCEIVER_VENDOR "vendor"
+#define TOPO_PORT_SFF_TRANSCEIVER_PN "part-number"
+#define TOPO_PORT_SFF_TRANSCEIVER_REV "revision"
+#define TOPO_PORT_SFF_TRANSCEIVER_SN "serial-number"
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
index 2a137ad388..e6dda440a0 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
@@ -22,6 +22,9 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
#ifndef _TOPO_MOD_H
#define _TOPO_MOD_H
@@ -215,6 +218,8 @@ extern void *topo_mod_zalloc(topo_mod_t *, size_t);
extern void topo_mod_free(topo_mod_t *, void *, size_t);
extern char *topo_mod_strdup(topo_mod_t *, const char *);
extern void topo_mod_strfree(topo_mod_t *, char *);
+extern char *topo_mod_strsplit(topo_mod_t *, const char *, const char *,
+ char **);
extern int topo_mod_nvalloc(topo_mod_t *, nvlist_t **, uint_t);
extern int topo_mod_nvdup(topo_mod_t *, nvlist_t *, nvlist_t **);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_string.c b/usr/src/lib/fm/topo/libtopo/common/topo_string.c
index 2c1f451770..2f59013e9e 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_string.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_string.c
@@ -23,8 +23,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
#include <strings.h>
#include <ctype.h>
@@ -56,6 +57,58 @@ topo_hdl_strfree(topo_hdl_t *thp, char *s)
}
char *
+topo_hdl_strsplit(topo_hdl_t *hdl, const char *input, const char *sep,
+ char **lastp)
+{
+ size_t seplen = strlen(sep);
+ const char *scanstart;
+ char *token;
+ char *ret;
+
+ if (input != NULL) {
+ /*
+ * Start scanning at beginning of input:
+ */
+ scanstart = input;
+ } else if (*lastp == NULL) {
+ /*
+ * If we have already finished scanning, return NULL.
+ */
+ return (NULL);
+ } else {
+ /*
+ * Otherwise, start scanning where we left off:
+ */
+ scanstart = *lastp;
+ }
+
+ token = strstr(scanstart, sep);
+ if (token != NULL) {
+ /*
+ * We still have a separator, so advance the next-start
+ * pointer past it:
+ */
+ *lastp = token + seplen;
+ /*
+ * Copy out this element. The buffer must fit the string
+ * exactly, so that topo_hdl_strfree() can determine its
+ * size with strlen().
+ */
+ ret = topo_hdl_alloc(hdl, token - scanstart + 1);
+ (void) strncpy(ret, scanstart, token - scanstart);
+ ret[token - scanstart] = '\0';
+ } else {
+ /*
+ * We have no separator, so this is the last element:
+ */
+ *lastp = NULL;
+ ret = topo_hdl_strdup(hdl, scanstart);
+ }
+
+ return (ret);
+}
+
+char *
topo_mod_strdup(topo_mod_t *mod, const char *s)
{
return (topo_hdl_strdup(mod->tm_hdl, s));
@@ -67,6 +120,13 @@ topo_mod_strfree(topo_mod_t *mod, char *s)
topo_hdl_strfree(mod->tm_hdl, s);
}
+char *
+topo_mod_strsplit(topo_mod_t *mod, const char *input, const char *sep,
+ char **lastp)
+{
+ return (topo_hdl_strsplit(mod->tm_hdl, input, sep, lastp));
+}
+
const char *
topo_strbasename(const char *s)
{
diff --git a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh
index 000742db71..874bad142f 100644..100755
--- a/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh
+++ b/usr/src/lib/fm/topo/maps/Joyent,Joyent-Compute-Platform-1101/Joyent-Compute-Platform-1101-disk-hc-topology.xmlgenksh
@@ -69,17 +69,19 @@ EOF
enclosure=1
bay=0
slot=0
-devctl='/devices/pci@0,0/pci8086,3c02@1/pci15d9,691@0:devctl'
+devctl0='/devices/pci@0,0/pci8086,3c02@1/pci15d9,691@0:devctl'
+devctl1='/devices/pci@0,0/pci8086,e02@1/pci15d9,691@0:devctl'
while (( slot <= 7 )); do
- do_node $bay "Front Disk $bay" "$devctl" $enclosure $slot
+ do_node $bay "Front Disk $bay" "$devctl0|$devctl1" $enclosure $slot
(( bay = bay + 1 ))
(( slot = slot + 1 ))
done
slot=0
-devctl='/devices/pci@0,0/pci8086,3c06@2,2/pci15d9,691@0:devctl'
+devctl0='/devices/pci@0,0/pci8086,3c06@2,2/pci15d9,691@0:devctl'
+devctl1='/devices/pci@0,0/pci8086,e06@2,2/pci15d9,691@0:devctl'
while (( slot <= 7 )); do
- do_node $bay "Front Disk $bay" "$devctl" $enclosure $slot
+ do_node $bay "Front Disk $bay" "$devctl0|$devctl1" $enclosure $slot
(( bay = bay + 1 ))
(( slot = slot + 1 ))
done
diff --git a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
index fda43bca6c..7d8f85fd88 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
+++ b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml
@@ -2,7 +2,7 @@
<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
<!--
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
-Copyright (c) 2013, Joyent, Inc. All rights reserved.
+Copyright (c) 2014, Joyent, Inc. All rights reserved.
CDDL HEADER START
@@ -152,7 +152,7 @@ Copyright (c) 2013, Joyent, Inc. All rights reserved.
</range>
</set>
- <set type='product' setlist='Joyent-Compute-Platform-1101|Joyent-Compute-Platform-1102'>
+ <set type='product' setlist='Joyent-Compute-Platform-1101|Joyent-Compute-Platform-1102|Joyent-Compute-Platform-2101|Joyent-Compute-Platform-2102'>
<range name='psu' min='0' max='1'>
<enum-method name='ipmi' version='1' />
</range>
diff --git a/usr/src/lib/fm/topo/modules/Makefile.plugin b/usr/src/lib/fm/topo/modules/Makefile.plugin
index 7eef744f46..13d90b8a27 100644
--- a/usr/src/lib/fm/topo/modules/Makefile.plugin
+++ b/usr/src/lib/fm/topo/modules/Makefile.plugin
@@ -56,7 +56,7 @@ plat_ROOTCONF = $(PLATFORMS:%=$(ROOT)/usr/platform/%/lib/fm/topo/plugins/$(CONF)
ROOTCONF = $($(CLASS)_ROOTCONF)
LINTFLAGS = -msux
-LINTFILES = $(SRCS:%.c=%.ln)
+LINTFILES = $(MODULESRCS:%.c=%.ln) $(SHAREDSRCS:%.c=%.ln)
CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-parentheses
@@ -105,6 +105,9 @@ clobber: clean
%.ln: ../../common/$(MODULE)/%.c
$(LINT.c) -c $<
+%.ln: ../../common/$(SHAREDMODULE)/%.c
+ $(LINT.c) -c $<
+
%.ln: %.c
$(LINT.c) -c $<
diff --git a/usr/src/lib/fm/topo/modules/common/Makefile b/usr/src/lib/fm/topo/modules/common/Makefile
index fa38496755..d725016aef 100644
--- a/usr/src/lib/fm/topo/modules/common/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/Makefile
@@ -22,6 +22,7 @@
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright (c) 2017, Joyent, Inc.
#
SUBDIRS = \
@@ -29,6 +30,7 @@ SUBDIRS = \
fac_prov_ipmi \
fac_prov_mptsas \
ipmi \
+ nic \
ses \
xfp
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c b/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c
index db853c6695..beae89f9f1 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_mptsas.c
@@ -32,11 +32,18 @@
#include "disk.h"
#include "disk_drivers.h"
+/*
+ * Request the SAS address of the disk (if any) attached to this mpt_sas
+ * instance at (Enclosure Number, Slot Number). The function returns
+ * -1 on error and sets errno to ENOENT _only_ if the /devices node
+ * (*devctl) does not exist.
+ */
static int
get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
uint32_t slot, char **sas_address)
{
- int fd, err, i;
+ int ret = -1, en = ENXIO;
+ int fd, i;
mptsas_get_disk_info_t gdi;
mptsas_disk_info_t *di;
size_t disz;
@@ -44,16 +51,19 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
bzero(&gdi, sizeof (gdi));
if ((fd = open(devctl, O_RDWR)) == -1) {
+ en = errno;
topo_mod_dprintf(mod, "could not open '%s' for ioctl: %s\n",
devctl, strerror(errno));
+ errno = en;
return (-1);
}
if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
+ if (errno != ENOENT)
+ en = errno;
topo_mod_dprintf(mod, "ioctl 1 on '%s' failed: %s\n", devctl,
strerror(errno));
- (void) close(fd);
- return (-1);
+ goto out;
}
gdi.DiskInfoArraySize = disz = sizeof (mptsas_disk_info_t) *
@@ -61,19 +71,19 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
gdi.PtrDiskInfoArray = di = topo_mod_alloc(mod, disz);
if (di == NULL) {
topo_mod_dprintf(mod, "memory allocation failed\n");
- (void) close(fd);
- return (-1);
+ en = ENOMEM;
+ goto out;
}
if (ioctl(fd, MPTIOCTL_GET_DISK_INFO, &gdi) == -1) {
+ if (errno != ENOENT)
+ en = errno;
topo_mod_dprintf(mod, "ioctl 2 on '%s' failed: %s\n", devctl,
strerror(errno));
topo_mod_free(mod, di, disz);
- (void) close(fd);
- return (-1);
+ goto out;
}
- err = -1;
for (i = 0; i < gdi.DiskCount; i++) {
if (di[i].Enclosure == enclosure && di[i].Slot == slot) {
char sas[17]; /* 16 hex digits and NUL */
@@ -81,14 +91,16 @@ get_sas_address(topo_mod_t *mod, char *devctl, uint32_t enclosure,
topo_mod_dprintf(mod, "found mpt_sas disk (%d/%d) "
"with adddress %s\n", enclosure, slot, sas);
*sas_address = topo_mod_strdup(mod, sas);
- err = 0;
+ en = ret = 0;
break;
}
}
topo_mod_free(mod, di, disz);
+out:
(void) close(fd);
- return (err);
+ errno = en;
+ return (ret);
}
int
@@ -97,6 +109,8 @@ disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
char *devctl = NULL;
uint32_t enclosure, slot;
int err;
+ char *elem, *lastp;
+ int ret = -1;
/*
* Get the required properties from the node. These come from
@@ -115,6 +129,35 @@ disk_mptsas_find_disk(topo_mod_t *mod, tnode_t *baynode, char **sas_address)
return (-1);
}
- return (get_sas_address(mod, devctl, enclosure, slot, sas_address));
+ /*
+ * devctl is a (potentially) pipe-separated list of different device
+ * paths to try.
+ */
+ if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) != NULL) {
+ boolean_t done = B_FALSE;
+ do {
+ topo_mod_dprintf(mod, "trying mpt_sas instance at %s\n",
+ elem);
+
+ ret = get_sas_address(mod, elem, enclosure,
+ slot, sas_address);
+
+ /*
+ * Only try further devctl paths from the list if this
+ * one was not found:
+ */
+ if (ret == 0 || errno != ENOENT) {
+ done = B_TRUE;
+ } else {
+ topo_mod_dprintf(mod, "instance not found\n");
+ }
+
+ topo_mod_strfree(mod, elem);
+
+ } while (!done && (elem = topo_mod_strsplit(mod, NULL, "|",
+ &lastp)) != NULL);
+ }
+ topo_mod_strfree(mod, devctl);
+ return (ret);
}
diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c b/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c
index a49a131811..115e3b801d 100644
--- a/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c
+++ b/usr/src/lib/fm/topo/modules/common/fac_prov_mptsas/fac_prov_mptsas.c
@@ -72,6 +72,12 @@ _topo_fini(topo_mod_t *mod)
topo_mod_unregister(mod);
}
+/*
+ * Get or set LED state for a particular target attached to an mpt_sas
+ * instance at (Enclosure Number, Slot Number). The function returns
+ * -1 on error and sets errno to ENOENT _only_ if the /devices node
+ * (*devctl) does not exist.
+ */
static int
do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
uint16_t slot, uint8_t led, uint32_t *ledmode, boolean_t set)
@@ -88,8 +94,10 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
lc.LedStatus = *ledmode;
if ((fd = open(devctl, (set ? O_RDWR : O_RDONLY))) == -1) {
+ int en = errno;
topo_mod_dprintf(mod, "devctl open failed: %s",
strerror(errno));
+ errno = en;
return (-1);
}
@@ -103,9 +111,11 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
*/
lc.LedStatus = 0;
} else {
+ int en = errno;
topo_mod_dprintf(mod, "led control ioctl failed: %s",
strerror(errno));
(void) close(fd);
+ errno = en;
return (-1);
}
}
@@ -113,6 +123,7 @@ do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
*ledmode = lc.LedStatus ? TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF;
(void) close(fd);
+ errno = 0;
return (0);
}
@@ -127,7 +138,8 @@ mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
char *driver = NULL, *devctl = NULL;
uint32_t enclosure, slot;
uint8_t mptsas_led;
- boolean_t set;
+ boolean_t set, done;
+ char *elem, *lastp;
if (vers > TOPO_METH_MPTSAS_LED_MODE_VERSION)
return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
@@ -197,8 +209,41 @@ mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__);
}
- if (do_led_control(mod, devctl, enclosure, slot, mptsas_led, &ledmode,
- set) != 0) {
+ /*
+ * devctl is a (potentially) pipe-separated list of different device
+ * paths to try.
+ */
+ if ((elem = topo_mod_strsplit(mod, devctl, "|", &lastp)) == NULL) {
+ topo_mod_dprintf(mod, "%s: could not parse devctl list",
+ __func__);
+ ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
+ goto out;
+ }
+ done = B_FALSE;
+ do {
+ topo_mod_dprintf(mod, "%s: trying mpt_sas instance at %s\n",
+ __func__, elem);
+
+ ret = do_led_control(mod, elem, enclosure, slot,
+ mptsas_led, &ledmode, set);
+
+ /*
+ * Only try further devctl paths from the list if this one
+ * was not found:
+ */
+ if (ret == 0 || errno != ENOENT) {
+ done = B_TRUE;
+ } else {
+ topo_mod_dprintf(mod, "%s: instance not found\n",
+ __func__);
+ }
+
+ topo_mod_strfree(mod, elem);
+
+ } while (!done && (elem = topo_mod_strsplit(mod, NULL, "|",
+ &lastp)) != NULL);
+
+ if (ret != 0) {
topo_mod_dprintf(mod, "%s: do_led_control failed", __func__);
ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
goto out;
diff --git a/usr/src/lib/fm/topo/modules/common/nic/Makefile b/usr/src/lib/fm/topo/modules/common/nic/Makefile
new file mode 100644
index 0000000000..084b49dcd1
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/nic/Makefile
@@ -0,0 +1,26 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017, Joyent, Inc.
+#
+
+MODULE = nic
+CLASS = common
+SHAREDMODULE = shared
+
+MODULESRCS = topo_nic.c
+SHAREDSRCS = topo_port.c topo_transceiver.c
+
+include ../../Makefile.plugin
+
+CPPFLAGS += -I../shared
+LDLIBS += -ldevinfo -ldladm -lsff
diff --git a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c
new file mode 100644
index 0000000000..51c37142c5
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.c
@@ -0,0 +1,241 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+/*
+ * This module covers enumerating properties of physical NICs. At this time, as
+ * various devices are discovered that may relate to various networking gear, we
+ * will attempt to enumerate ports and transceivers under them, if requested.
+ */
+
+#include <strings.h>
+#include <libdevinfo.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <libsff.h>
+#include <unistd.h>
+#include <sys/dld_ioc.h>
+#include <sys/dld.h>
+
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_list.h>
+#include <fm/topo_method.h>
+
+#include <topo_port.h>
+#include <topo_transceiver.h>
+
+#include "topo_nic.h"
+
+/*
+ * Create an instance of a transceiver with the specified id. We must create
+ * both its port and the transceiver node.
+ */
+static int
+nic_create_transceiver(topo_mod_t *mod, tnode_t *pnode, dladm_handle_t handle,
+ datalink_id_t linkid, uint_t tranid)
+{
+ int ret;
+ tnode_t *port;
+ dld_ioc_gettran_t dgt;
+ dld_ioc_tranio_t dti;
+ uint8_t buf[256];
+ char ouibuf[16];
+ char *vendor = NULL, *part = NULL, *rev = NULL, *serial = NULL;
+ nvlist_t *nvl = NULL;
+
+ if ((ret = port_create_sff(mod, pnode, tranid, &port)) != 0)
+ return (ret);
+
+ bzero(&dgt, sizeof (dgt));
+ dgt.dgt_linkid = linkid;
+ dgt.dgt_tran_id = tranid;
+
+ if (ioctl(dladm_dld_fd(handle), DLDIOC_GETTRAN, &dgt) != 0) {
+ if (errno == ENOTSUP)
+ return (0);
+ return (-1);
+ }
+
+ if (dgt.dgt_present == 0)
+ return (0);
+
+ bzero(&dti, sizeof (dti));
+ dti.dti_linkid = linkid;
+ dti.dti_tran_id = tranid;
+ dti.dti_page = 0xa0;
+ dti.dti_nbytes = sizeof (buf);
+ dti.dti_buf = (uintptr_t)buf;
+
+ if (ioctl(dladm_dld_fd(handle), DLDIOC_READTRAN, &dti) == 0) {
+ uchar_t *oui;
+ uint_t nbyte;
+
+ if (libsff_parse(buf, dti.dti_nbytes, dti.dti_page,
+ &nvl) == 0) {
+ if ((ret = nvlist_lookup_string(nvl, LIBSFF_KEY_VENDOR,
+ &vendor)) != 0 && nvlist_lookup_byte_array(nvl,
+ LIBSFF_KEY_OUI, &oui, &nbyte) == 0 && nbyte == 3) {
+ if (snprintf(ouibuf, sizeof (ouibuf),
+ "%02x:%02x:%02x", oui[0], oui[1], oui[2]) <
+ sizeof (ouibuf)) {
+ vendor = ouibuf;
+ }
+ } else if (ret != 0) {
+ vendor = NULL;
+ }
+
+ if (nvlist_lookup_string(nvl, LIBSFF_KEY_PART,
+ &part) != 0) {
+ part = NULL;
+ }
+
+ if (nvlist_lookup_string(nvl, LIBSFF_KEY_REVISION,
+ &rev) != 0) {
+ rev = NULL;
+ }
+
+ if (nvlist_lookup_string(nvl, LIBSFF_KEY_SERIAL,
+ &serial) != 0) {
+ serial = NULL;
+ }
+ }
+ }
+
+ if (transceiver_range_create(mod, port, 0, 0) != 0) {
+ nvlist_free(nvl);
+ return (-1);
+ }
+
+ if (transceiver_create_sff(mod, port, 0, dgt.dgt_usable, vendor, part,
+ rev, serial, NULL) != 0) {
+ nvlist_free(nvl);
+ return (-1);
+ }
+
+ nvlist_free(nvl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+nic_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
+ topo_instance_t min, topo_instance_t max, void *modarg, void *data)
+{
+ di_node_t din = data;
+ datalink_id_t linkid;
+ dladm_handle_t handle;
+ dld_ioc_gettran_t dgt;
+ uint_t ntrans, i;
+ char dname[MAXNAMELEN];
+
+ if (strcmp(name, NIC) != 0) {
+ topo_mod_dprintf(mod, "nic_enum: asked to enumerate unknown "
+ "component: %s\n", name);
+ return (-1);
+ }
+
+ if (din == NULL) {
+ topo_mod_dprintf(mod, "nic_enum: missing data argument\n");
+ return (-1);
+ }
+
+ if ((handle = topo_mod_getspecific(mod)) == NULL) {
+ topo_mod_dprintf(mod, "nic_enum: failed to get nic module "
+ "specific data\n");
+ return (-1);
+ }
+
+ if (snprintf(dname, sizeof (dname), "%s%d", di_driver_name(din),
+ di_instance(din)) >= sizeof (dname)) {
+ topo_mod_dprintf(mod, "nic_enum: device name overflowed "
+ "internal buffer\n");
+ return (-1);
+ }
+
+ if (dladm_dev2linkid(handle, dname, &linkid) != DLADM_STATUS_OK)
+ return (-1);
+
+ bzero(&dgt, sizeof (dgt));
+ dgt.dgt_linkid = linkid;
+ dgt.dgt_tran_id = DLDIOC_GETTRAN_GETNTRAN;
+
+ if (ioctl(dladm_dld_fd(handle), DLDIOC_GETTRAN, &dgt) != 0) {
+ if (errno == ENOTSUP)
+ return (0);
+ return (-1);
+ }
+
+ ntrans = dgt.dgt_tran_id;
+ if (ntrans == 0)
+ return (0);
+
+ if (port_range_create(mod, pnode, 0, ntrans - 1) != 0)
+ return (-1);
+
+ for (i = 0; i < ntrans; i++) {
+ if (nic_create_transceiver(mod, pnode, handle, linkid, i) != 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+static const topo_modops_t nic_ops = {
+ nic_enum, NULL
+};
+
+static topo_modinfo_t nic_mod = {
+ NIC, FM_FMRI_SCHEME_HC, NIC_VERSION, &nic_ops
+};
+
+int
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+ dladm_handle_t handle;
+
+ if (getenv("TOPONICDEBUG") != NULL)
+ topo_mod_setdebug(mod);
+
+ topo_mod_dprintf(mod, "_mod_init: "
+ "initializing %s enumerator\n", NIC);
+
+ if (version != NIC_VERSION) {
+ return (-1);
+ }
+
+ if (dladm_open(&handle) != 0)
+ return (-1);
+
+ if (topo_mod_register(mod, &nic_mod, TOPO_VERSION) != 0) {
+ dladm_close(handle);
+ return (-1);
+ }
+
+ topo_mod_setspecific(mod, handle);
+
+ return (0);
+}
+
+void
+_topo_fini(topo_mod_t *mod)
+{
+ dladm_handle_t handle;
+
+ if ((handle = topo_mod_getspecific(mod)) == NULL)
+ return;
+
+ dladm_close(handle);
+ topo_mod_setspecific(mod, NULL);
+}
diff --git a/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h
new file mode 100644
index 0000000000..ba661542c4
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/nic/topo_nic.h
@@ -0,0 +1,34 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _TOPO_NIC_H
+#define _TOPO_NIC_H
+
+/*
+ * Common NIC module header file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NIC "nic"
+#define NIC_VERSION 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TOPO_NIC_H */
diff --git a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c
index 1f3ba4478e..36dc26aa8d 100644
--- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c
+++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#include <sys/fm/protocol.h>
@@ -43,6 +44,7 @@
#include <did.h>
#include <did_props.h>
#include <util.h>
+#include <topo_nic.h>
extern txprop_t Bus_common_props[];
extern txprop_t Dev_common_props[];
@@ -489,40 +491,52 @@ declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din,
*/
else if (class == PCI_CLASS_NET &&
di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 &&
- di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0) {
- if (vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) {
- /*
- * Is this an adapter card? Check the bus's physlot
- */
- dp = did_find(mod, topo_node_getspecific(bus));
- if (did_physlot(dp) >= 0) {
- topo_mod_dprintf(mod, "Found Neptune slot\n");
- (void) topo_mod_enummap(mod, fn,
- "xfp", FM_FMRI_SCHEME_HC);
+ di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0 &&
+ vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) {
+ /*
+ * Is this an adapter card? Check the bus's physlot
+ */
+ dp = did_find(mod, topo_node_getspecific(bus));
+ if (did_physlot(dp) >= 0) {
+ topo_mod_dprintf(mod, "Found Neptune slot\n");
+ (void) topo_mod_enummap(mod, fn,
+ "xfp", FM_FMRI_SCHEME_HC);
+ } else {
+ topo_mod_dprintf(mod, "Found Neptune ASIC\n");
+ if (topo_mod_load(mod, XAUI, TOPO_VERSION) == NULL) {
+ topo_mod_dprintf(mod, "pcibus enum "
+ "could not load xaui enum\n");
+ (void) topo_mod_seterrno(mod,
+ EMOD_PARTIAL_ENUM);
+ return;
} else {
- topo_mod_dprintf(mod, "Found Neptune ASIC\n");
- if (topo_mod_load(mod, XAUI, TOPO_VERSION) ==
- NULL) {
- topo_mod_dprintf(mod, "pcibus enum "
- "could not load xaui enum\n");
- (void) topo_mod_seterrno(mod,
- EMOD_PARTIAL_ENUM);
+ if (topo_node_range_create(mod, fn,
+ XAUI, 0, 1) < 0) {
+ topo_mod_dprintf(mod,
+ "child_range_add for "
+ "XAUI failed: %s\n",
+ topo_strerror(
+ topo_mod_errno(mod)));
return;
- } else {
- if (topo_node_range_create(mod, fn,
- XAUI, 0, 1) < 0) {
- topo_mod_dprintf(mod,
- "child_range_add for "
- "XAUI failed: %s\n",
- topo_strerror(
- topo_mod_errno(mod)));
- return;
- }
- (void) topo_mod_enumerate(mod, fn,
- XAUI, XAUI, fnno, fnno, fn);
}
+ (void) topo_mod_enumerate(mod, fn,
+ XAUI, XAUI, fnno, fnno, fn);
}
}
+ } else if (class == PCI_CLASS_NET) {
+ /*
+ * Ask the nic module if there are any nodes that need to be
+ * enumerated under this device. This might include things like
+ * transceivers or some day, LEDs.
+ */
+ if (topo_mod_load(mod, NIC, NIC_VERSION) == NULL) {
+ topo_mod_dprintf(mod, "pcibus enum could not load "
+ "nic enum\n");
+ (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+ return;
+ }
+
+ (void) topo_mod_enumerate(mod, fn, NIC, NIC, 0, 0, din);
} else if (class == PCI_CLASS_MASS) {
di_node_t cn;
int niports = 0;
diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.c b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c
new file mode 100644
index 0000000000..29efcf6bd9
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.c
@@ -0,0 +1,130 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_list.h>
+#include <fm/topo_method.h>
+
+#include <topo_port.h>
+
+/*
+ * Common routines to create port entries in the topology tree.
+ */
+
+static const topo_pgroup_info_t port_pgroup = {
+ TOPO_PGROUP_PORT,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+int
+port_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
+ topo_instance_t max)
+{
+ return (topo_node_range_create(mod, pnode, PORT, min, max));
+}
+
+/*
+ * Create a port node, specifying the type of port it is. This will create the
+ * common port property group and populate it. The caller will need to populate
+ * the port-specific property group as needed.
+ */
+static tnode_t *
+port_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
+ const char *type)
+{
+ int err;
+ tnode_t *tn = NULL;
+ nvlist_t *fmri = NULL, *auth = NULL, *presource = NULL;
+
+ if (type == NULL) {
+ topo_mod_dprintf(mod, "port_create_common missing type "
+ "argument\n");
+ goto error;
+ }
+
+ if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, PORT,
+ inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ if ((tn = topo_node_bind(mod, pnode, PORT, inst, fmri)) == NULL) {
+ topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ /*
+ * The FRU is always set to the FMRI of the parent device for a port.
+ */
+ if (topo_node_resource(pnode, &presource, &err) != 0) {
+ topo_mod_dprintf(mod, "topo_node_resource() failed: %s\n",
+ topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_node_fru_set(tn, presource, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n",
+ topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_pgroup_create(tn, &port_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to create property group %s: "
+ "%s\n", TOPO_PGROUP_PORT, topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_prop_set_string(tn, TOPO_PGROUP_PORT, TOPO_PROP_PORT_TYPE,
+ TOPO_PROP_IMMUTABLE, type, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PROP_PORT_TYPE, topo_strerror(err));
+ goto error;
+ }
+
+ nvlist_free(fmri);
+ nvlist_free(auth);
+ nvlist_free(presource);
+ return (tn);
+error:
+ topo_node_unbind(tn);
+ nvlist_free(fmri);
+ nvlist_free(auth);
+ nvlist_free(presource);
+ return (tn);
+}
+
+int
+port_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
+ tnode_t **nodep)
+{
+ tnode_t *tn;
+
+ tn = port_create_common(mod, pnode, inst, TOPO_PROP_PORT_TYPE_SFF);
+ if (tn == NULL)
+ return (-1);
+ *nodep = tn;
+ return (0);
+}
diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_port.h b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h
new file mode 100644
index 0000000000..78ace0b0bb
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/shared/topo_port.h
@@ -0,0 +1,36 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _TOPO_PORT_H
+#define _TOPO_PORT_H
+
+/*
+ * Routines to manage and create ports.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int port_range_create(topo_mod_t *, tnode_t *, topo_instance_t,
+ topo_instance_t);
+extern int port_create_sff(topo_mod_t *, tnode_t *, topo_instance_t,
+ tnode_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TOPO_PORT_H */
diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c
new file mode 100644
index 0000000000..25c4276dab
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.c
@@ -0,0 +1,185 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_list.h>
+#include <fm/topo_method.h>
+
+/*
+ * Common routines to create transceiver entries in the topology tree.
+ */
+
+static const topo_pgroup_info_t transceiver_pgroup = {
+ TOPO_PGROUP_TRANSCEIVER,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+static const topo_pgroup_info_t sff_transceiver_pgroup = {
+ TOPO_PGROUP_SFF_TRANSCEIVER,
+ TOPO_STABILITY_PRIVATE,
+ TOPO_STABILITY_PRIVATE,
+ 1
+};
+
+int
+transceiver_range_create(topo_mod_t *mod, tnode_t *pnode, topo_instance_t min,
+ topo_instance_t max)
+{
+ return (topo_node_range_create(mod, pnode, TRANSCEIVER, min, max));
+}
+
+static tnode_t *
+transceiver_create_common(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
+ const char *type, boolean_t usable, const char *part, const char *rev,
+ const char *serial)
+{
+ int err;
+ tnode_t *tn = NULL;
+ nvlist_t *fmri = NULL, *auth = NULL;
+
+ if (type == NULL) {
+ topo_mod_dprintf(mod, "transceiver_create_common missing type "
+ "argument");
+ goto error;
+ }
+
+ if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_auth() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
+ TRANSCEIVER, inst, NULL, auth, part, rev, serial)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ if ((tn = topo_node_bind(mod, pnode, TRANSCEIVER, inst, fmri)) ==
+ NULL) {
+ topo_mod_dprintf(mod, "topo_node_bind() failed: %s\n",
+ topo_mod_errmsg(mod));
+ goto error;
+ }
+
+ /*
+ * The FRU for a transceiver is always itself.
+ */
+ if (topo_node_fru_set(tn, fmri, 0, &err) != 0) {
+ topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s\n",
+ topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_pgroup_create(tn, &transceiver_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to create property group %s: "
+ "%s\n", TOPO_PGROUP_TRANSCEIVER, topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
+ TOPO_PROP_TRANSCEIVER_TYPE, TOPO_PROP_IMMUTABLE, type,
+ &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PROP_TRANSCEIVER_TYPE, topo_strerror(err));
+ goto error;
+ }
+
+ if (topo_prop_set_string(tn, TOPO_PGROUP_TRANSCEIVER,
+ TOPO_PROP_TRANSCEIVER_USABLE, TOPO_PROP_IMMUTABLE,
+ usable ? "true" : "false", &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PROP_TRANSCEIVER_USABLE, topo_strerror(err));
+ goto error;
+ }
+
+ nvlist_free(fmri);
+ nvlist_free(auth);
+ return (tn);
+
+error:
+ topo_node_unbind(tn);
+ nvlist_free(fmri);
+ nvlist_free(auth);
+ return (NULL);
+}
+
+int
+transceiver_create_sff(topo_mod_t *mod, tnode_t *pnode, topo_instance_t inst,
+ boolean_t useable, const char *vendor, const char *part, const char *rev,
+ const char *serial, tnode_t **nodep)
+{
+ int err;
+ tnode_t *tn = NULL;
+
+ if ((tn = transceiver_create_common(mod, pnode, inst,
+ TOPO_PROP_PORT_TYPE_SFF, useable, part, rev, serial)) == NULL) {
+ return (-1);
+ }
+
+ /*
+ * Always create the SFF property group, even if we can't fill in any
+ * properties.
+ */
+ if (topo_pgroup_create(tn, &sff_transceiver_pgroup, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to create property group %s: "
+ "%s\n", TOPO_PGROUP_SFF_TRANSCEIVER, topo_strerror(err));
+ goto error;
+ }
+
+ if (vendor != NULL && topo_prop_set_string(tn,
+ TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_VENDOR,
+ TOPO_PROP_IMMUTABLE, vendor, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PORT_SFF_TRANSCEIVER_VENDOR, topo_strerror(err));
+ goto error;
+ }
+
+ if (part != NULL && topo_prop_set_string(tn,
+ TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_PN,
+ TOPO_PROP_IMMUTABLE, part, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PORT_SFF_TRANSCEIVER_PN, topo_strerror(err));
+ goto error;
+ }
+
+ if (rev != NULL && topo_prop_set_string(tn,
+ TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_REV,
+ TOPO_PROP_IMMUTABLE, rev, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PORT_SFF_TRANSCEIVER_REV, topo_strerror(err));
+ goto error;
+ }
+
+ if (serial != NULL && topo_prop_set_string(tn,
+ TOPO_PGROUP_SFF_TRANSCEIVER, TOPO_PORT_SFF_TRANSCEIVER_SN,
+ TOPO_PROP_IMMUTABLE, serial, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set %s property: %s\n",
+ TOPO_PORT_SFF_TRANSCEIVER_SN, topo_strerror(err));
+ goto error;
+ }
+
+ if (nodep != NULL)
+ *nodep = tn;
+ return (0);
+
+error:
+ topo_node_unbind(tn);
+ return (-1);
+}
diff --git a/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h
new file mode 100644
index 0000000000..f371598739
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/shared/topo_transceiver.h
@@ -0,0 +1,37 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _TOPO_TRANSCEIVER_H
+#define _TOPO_TRANSCEIVER_H
+
+/*
+ * Routines to manage and create ports.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int transceiver_range_create(topo_mod_t *, tnode_t *, topo_instance_t,
+ topo_instance_t);
+extern int transceiver_create_sff(topo_mod_t *, tnode_t *, topo_instance_t,
+ boolean_t, const char *, const char *, const char *, const char *,
+ tnode_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TOPO_TRANSCEIVER_H */
diff --git a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile
index 1b34ed3510..b41606985a 100644
--- a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile
+++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile
@@ -21,6 +21,7 @@
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, Joyent, Inc.
#
MODULE = pcibus
@@ -28,6 +29,7 @@ ARCH = i86pc
CLASS = arch
UTILDIR = ../../common/pcibus
HBDIR = ../../common/hostbridge
+NICDIR = ../../common/nic
UTILSRCS = did.c did_hash.c did_props.c util.c
PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c
@@ -37,4 +39,4 @@ include ../../Makefile.plugin
LDLIBS += -ldevinfo -lsmbios
-CPPFLAGS += -I$(UTILDIR) -I$(HBDIR)
+CPPFLAGS += -I$(UTILDIR) -I$(HBDIR) -I $(NICDIR)
diff --git a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci
index 277e868277..82ecb535c2 100644
--- a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci
+++ b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci
@@ -27,6 +27,7 @@ MODULE = pcibus
CLASS = arch
SUN4DIR = ../../sun4/$(MODULE)
UTILDIR = ../../common/pcibus
+NICDIR = ../../common/nic
HBDIR = ../../common/hostbridge
UTILSRCS = did.c did_hash.c did_props.c util.c
PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c
@@ -36,7 +37,7 @@ MODULESRCS = $(PCISRCS) $(UTILSRCS) pci_$(ARCH).c
include ../../Makefile.plugin
LDLIBS += -ldevinfo -lsmbios
-CPPFLAGS += -I$(SUN4DIR) -I$(UTILDIR) -I$(HBDIR)
+CPPFLAGS += -I$(SUN4DIR) -I$(UTILDIR) -I$(HBDIR) -I$(NICDIR)
%.o: $(SUN4DIR)/%.c
$(COMPILE.c) -o $@ $<
diff --git a/usr/src/lib/krb5/plugins/preauth/pkinit/Makefile.com b/usr/src/lib/krb5/plugins/preauth/pkinit/Makefile.com
index 8449d22e24..07fcb2bbf7 100644
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/Makefile.com
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/Makefile.com
@@ -70,7 +70,7 @@ CERRWARN += -_gcc=-Wno-unused-function
CFLAGS += $(CCVERBOSE) -I..
DYNFLAGS += $(KRUNPATH) $(KMECHLIB) -znodelete
-LDLIBS += -L $(ROOTLIBDIR) -lcrypto -lc
+LDLIBS += -L $(ROOTLIBDIR) -lsunw_crypto -lc
ROOTLIBDIR= $(ROOT)/usr/lib/krb5/plugins/preauth
diff --git a/usr/src/lib/libbc/inc/include/sys/socket.h b/usr/src/lib/libbc/inc/include/sys/socket.h
index 03961f805b..6607721e62 100644
--- a/usr/src/lib/libbc/inc/include/sys/socket.h
+++ b/usr/src/lib/libbc/inc/include/sys/socket.h
@@ -3,8 +3,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Copyright (c) 1982, 1985, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
@@ -169,6 +167,4 @@ struct msghdr {
#define MSG_PEEK 0x2 /* peek at incoming message */
#define MSG_DONTROUTE 0x4 /* send without using routing tables */
-#define MSG_MAXIOVLEN 16
-
#endif /*!_sys_socket_h*/
diff --git a/usr/src/lib/libbe/common/be_list.c b/usr/src/lib/libbe/common/be_list.c
index 373b8ef6e5..d56a9b6974 100644
--- a/usr/src/lib/libbe/common/be_list.c
+++ b/usr/src/lib/libbe/common/be_list.c
@@ -25,6 +25,7 @@
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2011 Joyent, Inc. All rights reserved.
* Copyright 2015 Toomas Soome <tsoome@me.com>
* Copyright 2015 Gary Mills
* Copyright (c) 2016 Martin Matuska. All rights reserved.
diff --git a/usr/src/lib/libbrand/common/libbrand.c b/usr/src/lib/libbrand/common/libbrand.c
index d0343acc47..dc406d60a0 100644
--- a/usr/src/lib/libbrand/common/libbrand.c
+++ b/usr/src/lib/libbrand/common/libbrand.c
@@ -323,6 +323,7 @@ i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size,
const char *curr_zone)
{
int dst, src;
+ static char *env_pool = NULL;
/*
* Walk through the characters, substituting values as needed.
@@ -339,6 +340,13 @@ i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size,
case '%':
dst += strlcpy(dbuf + dst, "%", dbuf_size - dst);
break;
+ case 'P':
+ if (env_pool == NULL)
+ env_pool = getenv("_ZONEADMD_ZPOOL");
+ if (env_pool == NULL)
+ break;
+ dst += strlcpy(dbuf + dst, env_pool, dbuf_size - dst);
+ break;
case 'R':
if (zonepath == NULL)
break;
@@ -817,6 +825,7 @@ i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonename,
xmlNodePtr node;
xmlChar *special, *dir, *type, *opt;
char special_exp[MAXPATHLEN];
+ char dir_exp[MAXPATHLEN];
char opt_exp[MAXPATHLEN];
int ret;
@@ -843,6 +852,10 @@ i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonename,
special_exp, sizeof (special_exp),
zonename, zonepath, NULL, NULL)) != 0)
goto next;
+ if ((ret = i_substitute_tokens((char *)dir,
+ dir_exp, sizeof (dir_exp),
+ zonename, zonepath, NULL, NULL)) != 0)
+ goto next;
/* opt might not be defined */
if (strlen((const char *)opt) == 0) {
@@ -855,7 +868,7 @@ i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonename,
goto next;
}
- ret = func(data, (char *)special_exp, (char *)dir,
+ ret = func(data, (char *)special_exp, (char *)dir_exp,
(char *)type, ((opt != NULL) ? opt_exp : NULL));
next:
diff --git a/usr/src/lib/libbsm/common/adt.c b/usr/src/lib/libbsm/common/adt.c
index 8c7b299e32..4cf0dd7566 100644
--- a/usr/src/lib/libbsm/common/adt.c
+++ b/usr/src/lib/libbsm/common/adt.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Joyent, Inc. All rights reserved.
*/
#include <bsm/adt.h>
@@ -702,7 +703,37 @@ adt_get_hostIP(const char *hostname, au_tid_addr_t *p_term)
int tries = 3;
char msg[512];
int eai_err;
+ struct ifaddrlist al;
+ int family;
+ boolean_t found = B_FALSE;
+ /*
+ * getaddrinfo can take a long time to timeout if it can't map the
+ * hostname to an IP address so try to get an IP address from a local
+ * interface first.
+ */
+ family = AF_INET6;
+ if (adt_get_local_address(family, &al) == 0) {
+ found = B_TRUE;
+ } else {
+ family = AF_INET;
+ if (adt_get_local_address(family, &al) == 0)
+ found = B_TRUE;
+ }
+
+ if (found) {
+ if (family == AF_INET) {
+ p_term->at_type = AU_IPv4;
+ (void) memcpy(p_term->at_addr, &al.addr.addr, AU_IPv4);
+ } else {
+ p_term->at_type = AU_IPv6;
+ (void) memcpy(p_term->at_addr, &al.addr.addr6, AU_IPv6);
+ }
+
+ return (0);
+ }
+
+ /* Now try getaddrinfo */
while ((tries-- > 0) &&
((eai_err = getaddrinfo(hostname, NULL, NULL, &ai)) != 0)) {
/*
@@ -739,7 +770,9 @@ adt_get_hostIP(const char *hostname, au_tid_addr_t *p_term)
}
freeaddrinfo(ai);
return (0);
- } else if (auditstate & (AUC_AUDITING | AUC_NOSPACE)) {
+ }
+
+ if (auditstate & (AUC_AUDITING | AUC_NOSPACE)) {
auditinfo_addr_t audit_info;
/*
@@ -747,58 +780,23 @@ adt_get_hostIP(const char *hostname, au_tid_addr_t *p_term)
* kernel audit context
*/
if (auditon(A_GETKAUDIT, (caddr_t)&audit_info,
- sizeof (audit_info)) < 0) {
- adt_write_syslog("unable to get kernel audit context",
- errno);
- goto try_interface;
+ sizeof (audit_info)) >= 0) {
+ adt_write_syslog("setting Audit IP address to kernel",
+ 0);
+ *p_term = audit_info.ai_termid;
+ return (0);
}
- adt_write_syslog("setting Audit IP address to kernel", 0);
- *p_term = audit_info.ai_termid;
- return (0);
+ adt_write_syslog("unable to get kernel audit context", errno);
}
-try_interface:
- {
- struct ifaddrlist al;
- int family;
- char ntop[INET6_ADDRSTRLEN];
-
- /*
- * getaddrinfo has failed to map the hostname
- * to an IP address, try to get an IP address
- * from a local interface. If none up, default
- * to loopback.
- */
- family = AF_INET6;
- if (adt_get_local_address(family, &al) != 0) {
- family = AF_INET;
-
- if (adt_get_local_address(family, &al) != 0) {
- adt_write_syslog("adt_get_local_address "
- "failed, no Audit IP address available, "
- "faking loopback and error",
- errno);
- IN_SET_LOOPBACK_ADDR(
- (struct sockaddr_in *)&(al.addr.addr));
- (void) memcpy(p_term->at_addr, &al.addr.addr,
- AU_IPv4);
- p_term->at_type = AU_IPv4;
- return (-1);
- }
- }
- if (family == AF_INET) {
- p_term->at_type = AU_IPv4;
- (void) memcpy(p_term->at_addr, &al.addr.addr, AU_IPv4);
- } else {
- p_term->at_type = AU_IPv6;
- (void) memcpy(p_term->at_addr, &al.addr.addr6, AU_IPv6);
- }
- (void) snprintf(msg, sizeof (msg), "mapping %s to %s",
- hostname, inet_ntop(family, &(al.addr), ntop,
- sizeof (ntop)));
- adt_write_syslog(msg, 0);
- return (0);
- }
+ /* No mapping, default to loopback. */
+ errno = ENETDOWN;
+ adt_write_syslog("adt_get_local_address failed, no Audit IP address "
+ "available, faking loopback and error", errno);
+ IN_SET_LOOPBACK_ADDR((struct sockaddr_in *)&(al.addr.addr));
+ (void) memcpy(p_term->at_addr, &al.addr.addr, AU_IPv4);
+ p_term->at_type = AU_IPv4;
+ return (-1);
}
/*
@@ -2093,8 +2091,8 @@ adt_selected(struct adt_event_state *event, au_event_t actual_id, int status)
}
/*
- * Can't map the host name to an IP address in
- * adt_get_hostIP. Get something off an interface
+ * Before trying to map the host name to an IP address in
+ * adt_get_hostIP, get something off an interface
* to act as the hosts IP address for auditing.
*/
diff --git a/usr/src/lib/libbunyan/Makefile b/usr/src/lib/libbunyan/Makefile
new file mode 100644
index 0000000000..a59de91113
--- /dev/null
+++ b/usr/src/lib/libbunyan/Makefile
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc.
+#
+
+include ../Makefile.lib
+
+HDRS = bunyan.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libbunyan/Makefile.com b/usr/src/lib/libbunyan/Makefile.com
new file mode 100644
index 0000000000..5214915c56
--- /dev/null
+++ b/usr/src/lib/libbunyan/Makefile.com
@@ -0,0 +1,36 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+LIBRARY = libbunyan.a
+VERS = .1
+OBJECTS = bunyan.o
+USDT_PROVIDERS = bunyan_provider.d
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lumem -lnvpair -lnsl
+CPPFLAGS += -I../common -I. -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
+include ../../Makefile.usdt
diff --git a/usr/src/lib/libbunyan/amd64/Makefile b/usr/src/lib/libbunyan/amd64/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/libbunyan/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libbunyan/common/bunyan.c b/usr/src/lib/libbunyan/common/bunyan.c
new file mode 100644
index 0000000000..149702a38f
--- /dev/null
+++ b/usr/src/lib/libbunyan/common/bunyan.c
@@ -0,0 +1,913 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <umem.h>
+#include <netdb.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/sysmacros.h>
+#include <thread.h>
+#include <sys/debug.h>
+
+#include <bunyan.h>
+#include <bunyan_provider_impl.h>
+
+struct bunyan_key;
+struct bunyan_stream;
+struct bunyan;
+
+typedef struct bunyan_stream {
+ struct bunyan_stream *bs_next;
+ char *bs_name;
+ bunyan_level_t bs_level;
+ bunyan_stream_f bs_func;
+ void *bs_arg;
+ uint_t bs_count;
+} bunyan_stream_t;
+
+typedef struct bunyan_key {
+ struct bunyan_key *bk_next;
+ char *bk_name;
+ bunyan_type_t bk_type;
+ void *bk_data;
+ size_t bk_len;
+} bunyan_key_t;
+
+typedef struct bunyan {
+ pthread_mutex_t bun_lock;
+ bunyan_key_t *bun_keys;
+ bunyan_stream_t *bun_streams;
+ char *bun_name;
+ char bun_host[MAXHOSTNAMELEN+1];
+} bunyan_t;
+
+#define ISO_TIMELEN 25
+static const int bunyan_version = 0;
+
+static void
+bunyan_key_fini(bunyan_key_t *bkp)
+{
+ size_t nlen = strlen(bkp->bk_name) + 1;
+ umem_free(bkp->bk_data, bkp->bk_len);
+ umem_free(bkp->bk_name, nlen);
+ umem_free(bkp, sizeof (bunyan_key_t));
+}
+
+static void
+bunyan_stream_fini(bunyan_stream_t *bsp)
+{
+ size_t nlen = strlen(bsp->bs_name) + 1;
+ umem_free(bsp->bs_name, nlen);
+ umem_free(bsp, sizeof (bunyan_stream_t));
+}
+
+int
+bunyan_init(const char *name, bunyan_logger_t **bhp)
+{
+ int ret;
+ bunyan_t *b;
+ size_t nlen = strlen(name) + 1;
+
+ b = umem_zalloc(sizeof (bunyan_t), UMEM_DEFAULT);
+ if (b == NULL)
+ return (ENOMEM);
+
+ b->bun_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (b->bun_name == NULL) {
+ umem_free(b, sizeof (bunyan_t));
+ return (ENOMEM);
+ }
+ bcopy(name, b->bun_name, nlen);
+
+ if ((ret = pthread_mutex_init(&b->bun_lock, NULL)) != 0) {
+ umem_free(b->bun_name, nlen);
+ umem_free(b, sizeof (bunyan_t));
+ return (ret);
+ }
+
+ VERIFY(gethostname(b->bun_host, sizeof (b->bun_host)) == 0);
+ b->bun_host[MAXHOSTNAMELEN] = '\0';
+
+ *bhp = (bunyan_logger_t *)b;
+ return (0);
+}
+
+void
+bunyan_fini(bunyan_logger_t *bhp)
+{
+ bunyan_t *b = (bunyan_t *)bhp;
+ bunyan_key_t *bkp;
+ bunyan_stream_t *bsp;
+
+ while ((bkp = b->bun_keys) != NULL) {
+ b->bun_keys = bkp->bk_next;
+ bunyan_key_fini(bkp);
+ }
+
+ while ((bsp = b->bun_streams) != NULL) {
+ b->bun_streams = bsp->bs_next;
+ bunyan_stream_fini(bsp);
+ }
+
+ if (b->bun_name != NULL)
+ umem_free(b->bun_name, strlen(b->bun_name) + 1);
+
+ VERIFY(pthread_mutex_destroy(&b->bun_lock) == 0);
+ umem_free(b, sizeof (bunyan_t));
+}
+
+/* ARGSUSED */
+int
+bunyan_stream_fd(nvlist_t *nvl, const char *js, void *arg)
+{
+ uintptr_t fd = (uintptr_t)arg;
+ size_t jslen = strlen(js);
+ off_t off = 0;
+ ssize_t ret = 0;
+ static int maxbuf = -1;
+
+ if (maxbuf == -1)
+ maxbuf = getpagesize();
+
+ while (off != jslen) {
+ /*
+ * Write up to a page of data at a time. If for some reason an
+ * individual write fails, move on and try to still write a new
+ * line at least...
+ */
+ ret = write(fd, js + off, MIN(jslen - off, maxbuf));
+ if (ret < 0)
+ break;
+ off += ret;
+ }
+
+ if (ret < 0) {
+ (void) write(fd, "\n", 1);
+ } else {
+ ret = write(fd, "\n", 1);
+ }
+ return (ret < 0 ? 1: 0);
+}
+
+int
+bunyan_stream_add(bunyan_logger_t *bhp, const char *name, int level,
+ bunyan_stream_f func, void *arg)
+{
+ bunyan_stream_t *bs, *cur;
+ size_t nlen = strlen(name) + 1;
+ bunyan_t *b = (bunyan_t *)bhp;
+
+ if (level != BUNYAN_L_TRACE &&
+ level != BUNYAN_L_DEBUG &&
+ level != BUNYAN_L_INFO &&
+ level != BUNYAN_L_WARN &&
+ level != BUNYAN_L_ERROR &&
+ level != BUNYAN_L_FATAL)
+ return (EINVAL);
+
+ bs = umem_alloc(sizeof (bunyan_stream_t), UMEM_DEFAULT);
+ if (bs == NULL)
+ return (ENOMEM);
+
+ bs->bs_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (bs->bs_name == NULL) {
+ umem_free(bs, sizeof (bunyan_stream_t));
+ return (ENOMEM);
+ }
+ bcopy(name, bs->bs_name, nlen);
+ bs->bs_level = level;
+ bs->bs_func = func;
+ bs->bs_arg = arg;
+ bs->bs_count = 0;
+ (void) pthread_mutex_lock(&b->bun_lock);
+ cur = b->bun_streams;
+ while (cur != NULL) {
+ if (strcmp(name, cur->bs_name) == 0) {
+ (void) pthread_mutex_unlock(&b->bun_lock);
+ umem_free(bs->bs_name, nlen);
+ umem_free(bs, sizeof (bunyan_stream_t));
+ return (EEXIST);
+ }
+ cur = cur->bs_next;
+ }
+ bs->bs_next = b->bun_streams;
+ b->bun_streams = bs;
+ (void) pthread_mutex_unlock(&b->bun_lock);
+
+ return (0);
+}
+
+int
+bunyan_stream_remove(bunyan_logger_t *bhp, const char *name)
+{
+ bunyan_stream_t *cur, *prev;
+ bunyan_t *b = (bunyan_t *)bhp;
+
+ (void) pthread_mutex_lock(&b->bun_lock);
+ prev = NULL;
+ cur = b->bun_streams;
+ while (cur != NULL) {
+ if (strcmp(name, cur->bs_name) == 0)
+ break;
+ prev = cur;
+ cur = cur->bs_next;
+ }
+ if (cur == NULL) {
+ (void) pthread_mutex_unlock(&b->bun_lock);
+ return (ENOENT);
+ }
+ if (prev == NULL)
+ b->bun_streams = cur->bs_next;
+ else
+ prev->bs_next = cur->bs_next;
+ cur->bs_next = NULL;
+ (void) pthread_mutex_unlock(&b->bun_lock);
+
+ bunyan_stream_fini(cur);
+
+ return (0);
+}
+
+static int
+bunyan_key_add_one(bunyan_t *b, const char *name, bunyan_type_t type,
+ const void *arg)
+{
+ bunyan_key_t *bkp, *cur, *prev;
+ size_t nlen = strlen(name) + 1;
+ size_t blen;
+
+ bkp = umem_alloc(sizeof (bunyan_key_t), UMEM_DEFAULT);
+ if (bkp == NULL)
+ return (ENOMEM);
+ bkp->bk_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (bkp->bk_name == NULL) {
+ umem_free(bkp, sizeof (bunyan_key_t));
+ return (ENOMEM);
+ }
+ bcopy(name, bkp->bk_name, nlen);
+
+ switch (type) {
+ case BUNYAN_T_STRING:
+ blen = strlen(arg) + 1;
+ break;
+ case BUNYAN_T_POINTER:
+ blen = sizeof (uintptr_t);
+ break;
+ case BUNYAN_T_IP:
+ blen = sizeof (struct in_addr);
+ break;
+ case BUNYAN_T_IP6:
+ blen = sizeof (struct in6_addr);
+ break;
+ case BUNYAN_T_BOOLEAN:
+ blen = sizeof (boolean_t);
+ break;
+ case BUNYAN_T_INT32:
+ blen = sizeof (int32_t);
+ break;
+ case BUNYAN_T_INT64:
+ case BUNYAN_T_INT64STR:
+ blen = sizeof (int64_t);
+ break;
+ case BUNYAN_T_UINT32:
+ blen = sizeof (uint32_t);
+ break;
+ case BUNYAN_T_UINT64:
+ case BUNYAN_T_UINT64STR:
+ blen = sizeof (uint64_t);
+ break;
+ case BUNYAN_T_DOUBLE:
+ blen = sizeof (double);
+ break;
+ default:
+ umem_free(bkp->bk_name, nlen);
+ umem_free(bkp, sizeof (bunyan_key_t));
+ return (EINVAL);
+ }
+
+ bkp->bk_data = umem_alloc(blen, UMEM_DEFAULT);
+ if (bkp->bk_data == NULL) {
+ umem_free(bkp->bk_name, nlen);
+ umem_free(bkp, sizeof (bunyan_key_t));
+ return (ENOMEM);
+ }
+ bcopy(arg, bkp->bk_data, blen);
+ bkp->bk_len = blen;
+ bkp->bk_type = type;
+
+ (void) pthread_mutex_lock(&b->bun_lock);
+ prev = NULL;
+ cur = b->bun_keys;
+ while (cur != NULL) {
+ if (strcmp(name, cur->bk_name) == 0)
+ break;
+ prev = cur;
+ cur = cur->bk_next;
+ }
+ if (cur != NULL) {
+ if (prev == NULL)
+ b->bun_keys = cur->bk_next;
+ else
+ prev->bk_next = cur->bk_next;
+ bunyan_key_fini(cur);
+ }
+ bkp->bk_next = b->bun_keys;
+ b->bun_keys = bkp;
+ (void) pthread_mutex_unlock(&b->bun_lock);
+
+ return (0);
+}
+
+static int
+bunyan_key_vadd(bunyan_t *b, va_list *ap)
+{
+ int type, ret;
+ void *data;
+ boolean_t bt;
+ int32_t i32;
+ int64_t i64;
+ uint32_t ui32;
+ uint64_t ui64;
+ double d;
+ uintptr_t ptr;
+
+ while ((type = va_arg(*ap, int)) != BUNYAN_T_END) {
+ const char *name = va_arg(*ap, char *);
+
+ switch (type) {
+ case BUNYAN_T_STRING:
+ data = va_arg(*ap, char *);
+ break;
+ case BUNYAN_T_POINTER:
+ ptr = (uintptr_t)va_arg(*ap, void *);
+ data = &ptr;
+ break;
+ case BUNYAN_T_IP:
+ case BUNYAN_T_IP6:
+ data = va_arg(*ap, void *);
+ break;
+ case BUNYAN_T_BOOLEAN:
+ bt = va_arg(*ap, boolean_t);
+ data = &bt;
+ break;
+ case BUNYAN_T_INT32:
+ i32 = va_arg(*ap, int32_t);
+ data = &i32;
+ break;
+ case BUNYAN_T_INT64:
+ case BUNYAN_T_INT64STR:
+ i64 = va_arg(*ap, int64_t);
+ data = &i64;
+ break;
+ case BUNYAN_T_UINT32:
+ ui32 = va_arg(*ap, uint32_t);
+ data = &ui32;
+ break;
+ case BUNYAN_T_UINT64:
+ case BUNYAN_T_UINT64STR:
+ ui64 = va_arg(*ap, uint64_t);
+ data = &ui64;
+ break;
+ case BUNYAN_T_DOUBLE:
+ d = va_arg(*ap, double);
+ data = &d;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if ((ret = bunyan_key_add_one(b, name, type, data)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+int
+bunyan_key_add(bunyan_logger_t *bhp, ...)
+{
+ int ret;
+ va_list ap;
+ bunyan_t *b = (bunyan_t *)bhp;
+
+ va_start(ap, bhp);
+ ret = bunyan_key_vadd(b, &ap);
+ va_end(ap);
+
+ return (ret);
+}
+
+int
+bunyan_key_remove(bunyan_logger_t *bhp, const char *name)
+{
+ bunyan_t *b = (bunyan_t *)bhp;
+ bunyan_key_t *cur, *prev;
+
+ (void) pthread_mutex_lock(&b->bun_lock);
+ prev = NULL;
+ cur = b->bun_keys;
+ while (cur != NULL) {
+ if (strcmp(name, cur->bk_name) == 0)
+ break;
+ prev = cur;
+ cur = cur->bk_next;
+ }
+
+ if (cur == NULL) {
+ (void) pthread_mutex_unlock(&b->bun_lock);
+ return (ENOENT);
+ }
+
+ if (prev == NULL)
+ b->bun_keys = cur->bk_next;
+ else
+ prev->bk_next = cur->bk_next;
+ (void) pthread_mutex_unlock(&b->bun_lock);
+
+ bunyan_key_fini(cur);
+ return (0);
+}
+
+static bunyan_key_t *
+bunyan_key_dup(const bunyan_key_t *bkp)
+{
+ bunyan_key_t *nkp;
+ size_t nlen = strlen(bkp->bk_name) + 1;
+
+ nkp = umem_alloc(sizeof (bunyan_key_t), UMEM_DEFAULT);
+ if (nkp == NULL)
+ return (NULL);
+ nkp->bk_next = NULL;
+ nkp->bk_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (nkp->bk_name == NULL) {
+ umem_free(nkp, sizeof (bunyan_key_t));
+ return (NULL);
+ }
+ bcopy(bkp->bk_name, nkp->bk_name, nlen);
+ nkp->bk_type = bkp->bk_type;
+ nkp->bk_data = umem_alloc(bkp->bk_len, UMEM_DEFAULT);
+ if (nkp->bk_data == NULL) {
+ umem_free(nkp->bk_name, nlen);
+ umem_free(nkp, sizeof (bunyan_key_t));
+ return (NULL);
+ }
+ bcopy(bkp->bk_data, nkp->bk_data, bkp->bk_len);
+ nkp->bk_len = bkp->bk_len;
+
+ return (nkp);
+}
+
+static bunyan_stream_t *
+bunyan_stream_dup(const bunyan_stream_t *bsp)
+{
+ bunyan_stream_t *nsp;
+ size_t nlen = strlen(bsp->bs_name) + 1;
+
+ nsp = umem_alloc(sizeof (bunyan_stream_t), UMEM_DEFAULT);
+ if (nsp == NULL)
+ return (NULL);
+
+ nsp->bs_next = NULL;
+ nsp->bs_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (nsp->bs_name == NULL) {
+ umem_free(nsp, sizeof (bunyan_stream_t));
+ return (NULL);
+ }
+ bcopy(bsp->bs_name, nsp->bs_name, nlen);
+ nsp->bs_level = bsp->bs_level;
+ nsp->bs_func = bsp->bs_func;
+ nsp->bs_arg = bsp->bs_arg;
+ nsp->bs_count = 0;
+
+ return (nsp);
+}
+
+static bunyan_t *
+bunyan_dup(const bunyan_t *b)
+{
+ bunyan_t *n;
+ const bunyan_key_t *bkp;
+ const bunyan_stream_t *bsp;
+ size_t nlen;
+
+ n = umem_zalloc(sizeof (bunyan_t), UMEM_DEFAULT);
+ if (n == NULL)
+ return (NULL);
+
+ if (pthread_mutex_init(&n->bun_lock, NULL) != 0) {
+ umem_free(n, sizeof (bunyan_t));
+ return (NULL);
+ }
+
+ for (bkp = b->bun_keys; bkp != NULL; bkp = bkp->bk_next) {
+ bunyan_key_t *nkp;
+ nkp = bunyan_key_dup(bkp);
+ if (nkp == NULL) {
+ bunyan_fini((bunyan_logger_t *)n);
+ return (NULL);
+ }
+
+ nkp->bk_next = n->bun_keys;
+ n->bun_keys = nkp;
+ }
+
+ for (bsp = b->bun_streams; bsp != NULL; bsp = bsp->bs_next) {
+ bunyan_stream_t *nsp;
+ nsp = bunyan_stream_dup(bsp);
+ if (bsp == NULL) {
+ bunyan_fini((bunyan_logger_t *)n);
+ return (NULL);
+ }
+
+ nsp->bs_next = n->bun_streams;
+ n->bun_streams = nsp;
+ }
+
+ nlen = strlen(b->bun_name) + 1;
+ n->bun_name = umem_alloc(nlen, UMEM_DEFAULT);
+ if (n->bun_name == NULL) {
+ bunyan_fini((bunyan_logger_t *)n);
+ return (NULL);
+ }
+ bcopy(b->bun_name, n->bun_name, nlen);
+ bcopy(b->bun_host, n->bun_host, MAXHOSTNAMELEN+1);
+
+ return (n);
+}
+
+int
+bunyan_child(const bunyan_logger_t *bhp, bunyan_logger_t **outp, ...)
+{
+ bunyan_t *b = (bunyan_t *)bhp;
+ bunyan_t *n;
+ va_list ap;
+ int ret;
+
+ n = bunyan_dup(b);
+ if (n == NULL)
+ return (ENOMEM);
+
+ va_start(ap, outp);
+ ret = bunyan_key_vadd(b, &ap);
+ va_end(ap);
+
+ if (ret != 0)
+ bunyan_fini((bunyan_logger_t *)n);
+ else
+ *outp = (bunyan_logger_t *)n;
+
+ return (ret);
+}
+
+static int
+bunyan_iso_time(char *buf)
+{
+ struct timeval tv;
+ struct tm tm;
+
+ if (gettimeofday(&tv, NULL) != 0)
+ return (errno);
+
+ if (gmtime_r(&tv.tv_sec, &tm) == NULL)
+ return (errno);
+
+ VERIFY(strftime(buf, ISO_TIMELEN, "%FT%T", &tm) == 19);
+
+ (void) snprintf(&buf[19], 6, ".%03dZ", (int)(tv.tv_usec / 1000));
+
+ return (0);
+}
+
+/*
+ * Note, these fields are all required, so even if a user attempts to use one of
+ * them in their own fields, we'll override them and therefore, have it be the
+ * last one.
+ */
+static int
+bunyan_vlog_defaults(nvlist_t *nvl, bunyan_t *b, bunyan_level_t level,
+ const char *msg)
+{
+ int ret;
+ char tbuf[ISO_TIMELEN];
+
+ if ((ret = bunyan_iso_time(tbuf)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_int32(nvl, "v", bunyan_version)) != 0 ||
+ (ret = nvlist_add_int32(nvl, "level", level) != 0) ||
+ (ret = nvlist_add_string(nvl, "name", b->bun_name) != 0) ||
+ (ret = nvlist_add_string(nvl, "hostname", b->bun_host) != 0) ||
+ (ret = nvlist_add_int32(nvl, "pid", getpid()) != 0) ||
+ (ret = nvlist_add_uint32(nvl, "tid", thr_self()) != 0) ||
+ (ret = nvlist_add_string(nvl, "time", tbuf) != 0) ||
+ (ret = nvlist_add_string(nvl, "msg", msg) != 0))
+ return (ret);
+
+ return (0);
+}
+
+static int
+bunyan_vlog_add(nvlist_t *nvl, const char *key, bunyan_type_t type, void *arg)
+{
+ int ret;
+ uintptr_t *up;
+ struct in_addr *v4;
+ struct in6_addr *v6;
+
+ /*
+ * Our buffer needs to hold the string forms of pointers, IPv6 strings,
+ * etc. INET6_ADDRSTRLEN is large enough for all of these.
+ */
+ char buf[INET6_ADDRSTRLEN];
+
+ switch (type) {
+ case BUNYAN_T_STRING:
+ ret = nvlist_add_string(nvl, key, (char *)arg);
+ break;
+ case BUNYAN_T_POINTER:
+ up = arg;
+ (void) snprintf(buf, sizeof (buf), "0x%p", *up);
+ ret = nvlist_add_string(nvl, key, buf);
+ break;
+ case BUNYAN_T_IP:
+ v4 = arg;
+ VERIFY(inet_ntop(AF_INET, v4, buf, sizeof (buf)) != NULL);
+ ret = nvlist_add_string(nvl, key, buf);
+ break;
+ case BUNYAN_T_IP6:
+ v6 = arg;
+ VERIFY(inet_ntop(AF_INET6, v6, buf, sizeof (buf)) != NULL);
+ ret = nvlist_add_string(nvl, key, buf);
+ break;
+ case BUNYAN_T_BOOLEAN:
+ ret = nvlist_add_boolean_value(nvl, key, *(boolean_t *)arg);
+ break;
+ case BUNYAN_T_INT32:
+ ret = nvlist_add_int32(nvl, key, *(int32_t *)arg);
+ break;
+ case BUNYAN_T_INT64:
+ ret = nvlist_add_int64(nvl, key, *(int64_t *)arg);
+ break;
+ case BUNYAN_T_UINT32:
+ ret = nvlist_add_uint32(nvl, key, *(uint32_t *)arg);
+ break;
+ case BUNYAN_T_UINT64:
+ ret = nvlist_add_uint64(nvl, key, *(uint32_t *)arg);
+ break;
+ case BUNYAN_T_DOUBLE:
+ ret = nvlist_add_double(nvl, key, *(double *)arg);
+ break;
+ case BUNYAN_T_INT64STR:
+ (void) snprintf(buf, sizeof (buf), "%lld", *(int64_t *)arg);
+ ret = nvlist_add_string(nvl, key, buf);
+ break;
+ case BUNYAN_T_UINT64STR:
+ (void) snprintf(buf, sizeof (buf), "%llu", *(uint64_t *)arg);
+ ret = nvlist_add_string(nvl, key, buf);
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+
+ return (ret);
+}
+
+static int
+bunyan_vlog(bunyan_logger_t *bhp, bunyan_level_t level, const char *msg,
+ va_list *ap)
+{
+ nvlist_t *nvl = NULL;
+ int ret, type;
+ bunyan_key_t *bkp;
+ bunyan_stream_t *bsp;
+ char *buf = NULL;
+ bunyan_t *b = (bunyan_t *)bhp;
+
+ if (msg == NULL)
+ return (EINVAL);
+
+ (void) pthread_mutex_lock(&b->bun_lock);
+
+ if ((ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) {
+ (void) pthread_mutex_unlock(&b->bun_lock);
+ return (ret);
+ }
+
+ /*
+ * We add pre-defined keys, then go through and process the users keys,
+ * and finally go ahead and our defaults. If all that succeeds, then we
+ * can go ahead and call all the built-in logs.
+ */
+ for (bkp = b->bun_keys; bkp != NULL; bkp = bkp->bk_next) {
+ if ((ret = bunyan_vlog_add(nvl, bkp->bk_name, bkp->bk_type,
+ bkp->bk_data)) != 0)
+ goto out;
+ }
+
+ while ((type = va_arg(*ap, int)) != BUNYAN_T_END) {
+ void *data;
+ boolean_t bt;
+ int32_t i32;
+ int64_t i64;
+ uint32_t ui32;
+ uint64_t ui64;
+ double d;
+ uintptr_t ptr;
+ const char *key = va_arg(*ap, char *);
+
+ switch (type) {
+ case BUNYAN_T_STRING:
+ data = va_arg(*ap, char *);
+ break;
+ case BUNYAN_T_POINTER:
+ ptr = (uintptr_t)va_arg(*ap, void *);
+ data = &ptr;
+ break;
+ case BUNYAN_T_IP:
+ case BUNYAN_T_IP6:
+ data = va_arg(*ap, void *);
+ break;
+ case BUNYAN_T_BOOLEAN:
+ bt = va_arg(*ap, boolean_t);
+ data = &bt;
+ break;
+ case BUNYAN_T_INT32:
+ i32 = va_arg(*ap, int32_t);
+ data = &i32;
+ break;
+ case BUNYAN_T_INT64:
+ case BUNYAN_T_INT64STR:
+ i64 = va_arg(*ap, int64_t);
+ data = &i64;
+ break;
+ case BUNYAN_T_UINT32:
+ ui32 = va_arg(*ap, uint32_t);
+ data = &ui32;
+ break;
+ case BUNYAN_T_UINT64:
+ case BUNYAN_T_UINT64STR:
+ ui64 = va_arg(*ap, uint64_t);
+ data = &ui64;
+ break;
+ case BUNYAN_T_DOUBLE:
+ d = va_arg(*ap, double);
+ data = &d;
+ break;
+ default:
+ ret = EINVAL;
+ goto out;
+ }
+
+ if ((ret = bunyan_vlog_add(nvl, key, type, data)) != 0)
+ goto out;
+
+ }
+ /*
+ * This must be the last thing we do before we log to ensure that all of
+ * our defaults always make it out.
+ */
+ if ((ret = bunyan_vlog_defaults(nvl, b, level, msg)) != 0)
+ goto out;
+
+ if (nvlist_dump_json(nvl, &buf) < 0) {
+ ret = errno;
+ goto out;
+ }
+
+ /* Fire DTrace probes */
+ switch (level) {
+ case BUNYAN_L_TRACE:
+ BUNYAN_LOG_TRACE(buf);
+ break;
+ case BUNYAN_L_DEBUG:
+ BUNYAN_LOG_DEBUG(buf);
+ break;
+ case BUNYAN_L_INFO:
+ BUNYAN_LOG_INFO(buf);
+ break;
+ case BUNYAN_L_WARN:
+ BUNYAN_LOG_WARN(buf);
+ break;
+ case BUNYAN_L_ERROR:
+ BUNYAN_LOG_ERROR(buf);
+ break;
+ case BUNYAN_L_FATAL:
+ BUNYAN_LOG_FATAL(buf);
+ break;
+ }
+
+ for (bsp = b->bun_streams; bsp != NULL; bsp = bsp->bs_next) {
+ if (bsp->bs_level <= level)
+ if (bsp->bs_func(nvl, buf, bsp->bs_arg) != 0)
+ bsp->bs_count++;
+ }
+ ret = 0;
+out:
+ (void) pthread_mutex_unlock(&b->bun_lock);
+ if (buf != NULL)
+ nvlist_dump_json_free(nvl, buf);
+ if (nvl != NULL)
+ nvlist_free(nvl);
+ return (ret);
+}
+
+int
+bunyan_trace(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_TRACE, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
+
+int
+bunyan_debug(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_DEBUG, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
+
+int
+bunyan_info(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_INFO, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
+
+int
+bunyan_warn(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_WARN, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
+
+int
+bunyan_error(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_ERROR, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
+
+
+int
+bunyan_fatal(bunyan_logger_t *bhp, const char *msg, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, msg);
+ ret = bunyan_vlog(bhp, BUNYAN_L_FATAL, msg, &va);
+ va_end(va);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libbunyan/common/bunyan.h b/usr/src/lib/libbunyan/common/bunyan.h
new file mode 100644
index 0000000000..9a01f6f6cd
--- /dev/null
+++ b/usr/src/lib/libbunyan/common/bunyan.h
@@ -0,0 +1,88 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ */
+
+#ifndef _BUNYAN_H
+#define _BUNYAN_H
+
+/*
+ * C version of the bunyan logging format.
+ */
+
+#include <limits.h>
+#include <libnvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct bunyan_logger bunyan_logger_t;
+
+typedef enum bunyan_level {
+ BUNYAN_L_TRACE = 10,
+ BUNYAN_L_DEBUG = 20,
+ BUNYAN_L_INFO = 30,
+ BUNYAN_L_WARN = 40,
+ BUNYAN_L_ERROR = 50,
+ BUNYAN_L_FATAL = 60
+} bunyan_level_t;
+
+typedef enum bunyan_type {
+ BUNYAN_T_END = 0x0,
+ BUNYAN_T_STRING,
+ BUNYAN_T_POINTER,
+ BUNYAN_T_IP,
+ BUNYAN_T_IP6,
+ BUNYAN_T_BOOLEAN,
+ BUNYAN_T_INT32,
+ BUNYAN_T_INT64,
+ BUNYAN_T_UINT32,
+ BUNYAN_T_UINT64,
+ BUNYAN_T_DOUBLE,
+ BUNYAN_T_INT64STR,
+ BUNYAN_T_UINT64STR
+} bunyan_type_t;
+
+/*
+ * A handle is MT-safe, but not fork-safe.
+ */
+extern int bunyan_init(const char *, bunyan_logger_t **);
+extern int bunyan_child(const bunyan_logger_t *, bunyan_logger_t **, ...);
+extern void bunyan_fini(bunyan_logger_t *);
+
+/*
+ * Bunyan stream callbacks are guaranteed to be serialized.
+ */
+typedef int (*bunyan_stream_f)(nvlist_t *, const char *, void *);
+extern int bunyan_stream_fd(nvlist_t *, const char *, void *);
+
+extern int bunyan_stream_add(bunyan_logger_t *, const char *, int,
+ bunyan_stream_f, void *);
+extern int bunyan_stream_remove(bunyan_logger_t *, const char *);
+
+extern int bunyan_key_add(bunyan_logger_t *, ...);
+extern int bunyan_key_remove(bunyan_logger_t *, const char *);
+
+extern int bunyan_trace(bunyan_logger_t *, const char *msg, ...);
+extern int bunyan_debug(bunyan_logger_t *, const char *msg, ...);
+extern int bunyan_info(bunyan_logger_t *, const char *msg, ...);
+extern int bunyan_warn(bunyan_logger_t *, const char *msg, ...);
+extern int bunyan_error(bunyan_logger_t *, const char *msg, ...);
+extern int bunyan_fatal(bunyan_logger_t *, const char *msg, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BUNYAN_H */
diff --git a/usr/src/lib/libbunyan/common/bunyan_provider.d b/usr/src/lib/libbunyan/common/bunyan_provider.d
new file mode 100644
index 0000000000..d47ea75733
--- /dev/null
+++ b/usr/src/lib/libbunyan/common/bunyan_provider.d
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ */
+
+/*
+ * Bunyan DTrace provider
+ */
+provider bunyan {
+ probe log__trace(char *);
+ probe log__debug(char *);
+ probe log__info(char *);
+ probe log__warn(char *);
+ probe log__error(char *);
+ probe log__fatal(char *);
+};
+
+#pragma D attributes Stable/Stable/ISA provider bunyan provider
+#pragma D attributes Private/Private/Unknown provider bunyan module
+#pragma D attributes Private/Private/Unknown provider bunyan function
+#pragma D attributes Stable/Stable/ISA provider bunyan name
+#pragma D attributes Stable/Stable/ISA provider bunyan args
diff --git a/usr/src/lib/libbunyan/common/llib-lbunyan b/usr/src/lib/libbunyan/common/llib-lbunyan
new file mode 100644
index 0000000000..31f6a52aba
--- /dev/null
+++ b/usr/src/lib/libbunyan/common/llib-lbunyan
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <bunyan.h>
diff --git a/usr/src/lib/libbunyan/common/mapfile-vers b/usr/src/lib/libbunyan/common/mapfile-vers
new file mode 100644
index 0000000000..775af4ab45
--- /dev/null
+++ b/usr/src/lib/libbunyan/common/mapfile-vers
@@ -0,0 +1,53 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOS_1.0 {
+ global:
+ bunyan_init;
+ bunyan_child;
+ bunyan_fini;
+ bunyan_stream_fd;
+ bunyan_stream_add;
+ bunyan_stream_remove;
+ bunyan_key_add;
+ bunyan_key_remove;
+ bunyan_trace;
+ bunyan_debug;
+ bunyan_info;
+ bunyan_warn;
+ bunyan_error;
+ bunyan_fatal;
+};
+
+SYMBOL_VERSION ILLUMOSprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/libbunyan/i386/Makefile b/usr/src/lib/libbunyan/i386/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/libbunyan/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libbunyan/sparc/Makefile b/usr/src/lib/libbunyan/sparc/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/libbunyan/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libbunyan/sparcv9/Makefile b/usr/src/lib/libbunyan/sparcv9/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/libbunyan/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index 2fe0b7bafe..e5449fbbfc 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -21,7 +21,7 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2016 Joyent, Inc.
+# Copyright (c) 2017, Joyent, Inc.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2013 Garrett D'Amore <garrett@damore.org>
# Copyright 2017 Nexenta Systems, Inc.
@@ -887,6 +887,7 @@ PORTSYS= \
fcntl.o \
getpagesizes.o \
getpeerucred.o \
+ inotify.o \
inst_sync.o \
issetugid.o \
label.o \
@@ -1201,6 +1202,7 @@ $(PORTI18N_COND:%=pics/%) := \
pics/arc4random.o := CPPFLAGS += -I$(SRC)/common/crypto/chacha
pics/__clock_gettime.o := CPPFLAGS += $(COMMPAGE_CPPFLAGS)
+pics/gettimeofday.o := CPPFLAGS += $(COMMPAGE_CPPFLAGS)
.KEEP_STATE:
diff --git a/usr/src/lib/libc/amd64/gen/siginfolst.c b/usr/src/lib/libc/amd64/gen/siginfolst.c
index 8451dfbb4f..8b8a1b4669 100644
--- a/usr/src/lib/libc/amd64/gen/siginfolst.c
+++ b/usr/src/lib/libc/amd64/gen/siginfolst.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -188,6 +189,7 @@ static const struct siginfolist _sys_siginfolist_data[NSIG-1] = {
0, 0,
0, 0,
0, 0, /* SIGRTMIN+15 */
+ 0, 0, /* SIGRTMIN+16 */
0, 0, /* SIGRTMAX-15 */
0, 0,
0, 0,
diff --git a/usr/src/lib/libc/amd64/sys/gettimeofday.s b/usr/src/lib/libc/amd64/sys/gettimeofday.s
deleted file mode 100644
index 1948a008d4..0000000000
--- a/usr/src/lib/libc/amd64/sys/gettimeofday.s
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
- .file "gettimeofday.s"
-
-#include "SYS.h"
-
- ANSI_PRAGMA_WEAK(gettimeofday,function)
-
-/*
- * implements int gettimeofday(struct timeval *tp, void *tzp)
- *
- * note that tzp is always ignored
- */
-
- ENTRY(gettimeofday)
-/*
- * use long long gethrestime()
- */
- pushq %rdi /* pointer to timeval */
- SYSFASTTRAP(GETHRESTIME)
-/*
- * gethrestime trap returns seconds in %eax, nsecs in %edx
- * need to convert nsecs to usecs & store into area pointed
- * to by struct timeval * argument.
- */
- popq %rcx /* pointer to timeval */
- jrcxz 1f /* bail if we get a null pointer */
- movq %rax, (%rcx) /* store seconds into timeval ptr */
- movl $274877907, %eax /* divide by 1000 as impl. by gcc */
- imull %edx /* See Hacker's Delight pg 162 */
- sarl $6, %edx /* simplified by 0 <= nsec <= 1e9 */
- movq %rdx, 8(%rcx) /* store usecs into timeval ptr + 8. */
-1:
- RETC /* return 0 */
- SET_SIZE(gettimeofday)
-
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index 3edbed15e0..c81a7c62a1 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -21,7 +21,7 @@
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2016 Joyent, Inc.
+# Copyright (c) 2017, Joyent, Inc.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright 2013 Garrett D'Amore <garrett@damore.org>
# Copyright 2017 Nexenta Systems, Inc.
@@ -926,6 +926,7 @@ PORTSYS= \
fcntl.o \
getpagesizes.o \
getpeerucred.o \
+ inotify.o \
inst_sync.o \
issetugid.o \
label.o \
@@ -1268,6 +1269,7 @@ $(PORTI18N_COND:%=pics/%) := \
pics/arc4random.o := CPPFLAGS += -I$(SRC)/common/crypto/chacha
pics/__clock_gettime.o := CPPFLAGS += $(COMMPAGE_CPPFLAGS)
+pics/gettimeofday.o := CPPFLAGS += $(COMMPAGE_CPPFLAGS)
.KEEP_STATE:
diff --git a/usr/src/lib/libc/i386/gen/siginfolst.c b/usr/src/lib/libc/i386/gen/siginfolst.c
index 8451dfbb4f..8b8a1b4669 100644
--- a/usr/src/lib/libc/i386/gen/siginfolst.c
+++ b/usr/src/lib/libc/i386/gen/siginfolst.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -188,6 +189,7 @@ static const struct siginfolist _sys_siginfolist_data[NSIG-1] = {
0, 0,
0, 0,
0, 0, /* SIGRTMIN+15 */
+ 0, 0, /* SIGRTMIN+16 */
0, 0, /* SIGRTMAX-15 */
0, 0,
0, 0,
diff --git a/usr/src/lib/libc/i386/sys/gettimeofday.c b/usr/src/lib/libc/i386/sys/gettimeofday.c
new file mode 100644
index 0000000000..7539c2143e
--- /dev/null
+++ b/usr/src/lib/libc/i386/sys/gettimeofday.c
@@ -0,0 +1,50 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+
+#include "thr_uberdata.h"
+#include <cp_defs.h>
+
+#pragma weak _gettimeofday = gettimeofday
+
+extern int __clock_gettime_sys(clockid_t, timespec_t *);
+
+int
+gettimeofday(struct timeval *tv, void *tz)
+{
+ comm_page_t *cp = (comm_page_t *)__uberdata.ub_comm_page;
+
+ /*
+ * Perform a NULL check before attempting to store the result directly.
+ * The old fasttrop logic would perform this same check, but after the
+ * call into hrestime().
+ */
+ if (tv == NULL) {
+ return (0);
+ }
+
+ /*
+ * Since timeval and timespec structs feature the same effective types
+ * and layout of their members, the conversion can be done in-place.
+ */
+ if (cp != NULL && __cp_can_gettime(cp) != 0) {
+ __cp_clock_gettime_realtime(cp, (struct timespec *)tv);
+ } else {
+ __clock_gettime_sys(CLOCK_REALTIME, (struct timespec *)tv);
+ }
+ /* Convert from tv_nsec to tv_usec */
+ tv->tv_usec /= 1000;
+ return (0);
+}
diff --git a/usr/src/lib/libc/i386/sys/gettimeofday.s b/usr/src/lib/libc/i386/sys/gettimeofday.s
deleted file mode 100644
index 1e21601aba..0000000000
--- a/usr/src/lib/libc/i386/sys/gettimeofday.s
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
- .file "gettimeofday.s"
-
-#include "SYS.h"
-
- ANSI_PRAGMA_WEAK(gettimeofday,function)
-
-/
-/ implements int gettimeofday(struct timeval *tp, void *tzp)
-/
-/ note that tzp is always ignored
-/
-
- ENTRY(gettimeofday)
-/
-/ use long long gethrestime()
-/
- SYSFASTTRAP(GETHRESTIME)
-/
-/ gethrestime trap returns seconds in %eax, nsecs in %edx
-/ need to convert nsecs to usecs & store into area pointed
-/ to by struct timeval * argument.
-/
- movl 4(%esp), %ecx / put ptr to timeval in %ecx
- jecxz 1f / bail if we get a null pointer
- movl %eax, (%ecx) / store seconds into timeval ptr
- movl $274877907, %eax / divide by 1000 as impl. by gcc
- imull %edx / See Hacker's Delight pg 162
- sarl $6, %edx / simplified by 0 <= nsec <= 1e9
- movl %edx, 4(%ecx) / store usecs into timeval ptr + 4.
-1:
- RETC / return 0
- SET_SIZE(gettimeofday)
-
-
diff --git a/usr/src/lib/libc/inc/thr_inlines.h b/usr/src/lib/libc/inc/thr_inlines.h
index f7cdc6a6bd..66d811f25b 100644
--- a/usr/src/lib/libc/inc/thr_inlines.h
+++ b/usr/src/lib/libc/inc/thr_inlines.h
@@ -47,17 +47,19 @@
extern __GNU_INLINE ulwp_t *
_curthread(void)
{
-#if defined(__amd64)
ulwp_t *__value;
- __asm__ __volatile__("movq %%fs:0, %0" : "=r" (__value));
+ __asm__ __volatile__(
+#if defined(__amd64)
+ "movq %%fs:0, %0\n\t"
#elif defined(__i386)
- ulwp_t *__value;
- __asm__ __volatile__("movl %%gs:0, %0" : "=r" (__value));
+ "movl %%gs:0, %0\n\t"
#elif defined(__sparc)
- register ulwp_t *__value __asm__("g7");
+ ".register %%g7, #scratch\n\t"
+ "mov %%g7, %0\n\t"
#else
#error "port me"
#endif
+ : "=r" (__value));
return (__value);
}
diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h
index cf06379ed7..678f68895f 100644
--- a/usr/src/lib/libc/inc/thr_uberdata.h
+++ b/usr/src/lib/libc/inc/thr_uberdata.h
@@ -965,6 +965,7 @@ typedef struct uberdata {
int ndaemons; /* total number of THR_DAEMON threads/lwps */
pid_t pid; /* the current process's pid */
void (*sigacthandler)(int, siginfo_t *, void *);
+ int (*setctxt)(const ucontext_t *);
ulwp_t *lwp_stacks;
ulwp_t *lwp_laststack;
int nfreestack;
@@ -977,6 +978,7 @@ typedef struct uberdata {
robust_t **robustlocks; /* table of registered robust locks */
robust_t *robustlist; /* list of registered robust locks */
char *progname; /* the basename of the program, from argv[0] */
+ char *ub_broot; /* the root of the native code in the brand */
void *ub_comm_page; /* arch-specific comm page of kernel data */
struct uberdata **tdb_bootstrap;
tdb_t tdb; /* thread debug interfaces (for libc_db) */
@@ -1179,6 +1181,7 @@ typedef struct uberdata32 {
int ndaemons;
int pid;
caddr32_t sigacthandler;
+ caddr32_t setctxt;
caddr32_t lwp_stacks;
caddr32_t lwp_laststack;
int nfreestack;
@@ -1191,6 +1194,7 @@ typedef struct uberdata32 {
caddr32_t robustlocks;
caddr32_t robustlist;
caddr32_t progname;
+ caddr32_t ub_broot;
caddr32_t ub_comm_page;
caddr32_t tdb_bootstrap;
tdb32_t tdb;
@@ -1281,6 +1285,7 @@ extern void rwl_free(ulwp_t *);
extern void heldlock_exit(void);
extern void heldlock_free(ulwp_t *);
extern void sigacthandler(int, siginfo_t *, void *);
+extern int setctxt(const ucontext_t *);
extern void signal_init(void);
extern int sigequalset(const sigset_t *, const sigset_t *);
extern void mutex_setup(void);
diff --git a/usr/src/lib/libc/port/gen/getauxv.c b/usr/src/lib/libc/port/gen/getauxv.c
index 500675719c..4356a01392 100644
--- a/usr/src/lib/libc/port/gen/getauxv.c
+++ b/usr/src/lib/libc/port/gen/getauxv.c
@@ -24,9 +24,8 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "lint.h"
+#include "thr_uberdata.h"
#include <libc.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -38,6 +37,7 @@
#include <thread.h>
#include <synch.h>
#include <atomic.h>
+#include <limits.h>
static mutex_t auxlock = DEFAULTMUTEX;
@@ -59,11 +59,20 @@ _getaux(int type)
if (auxb == NULL) {
lmutex_lock(&auxlock);
if (auxb == NULL) {
+ uberdata_t *udp = curthread->ul_uberdata;
struct stat statb;
auxv_t *buf = NULL;
+ char *path = "/proc/self/auxv";
+ char pbuf[PATH_MAX];
int fd;
- if ((fd = open("/proc/self/auxv", O_RDONLY)) != -1 &&
+ if (udp->ub_broot != NULL) {
+ (void) snprintf(pbuf, sizeof (pbuf),
+ "%s/proc/self/auxv", udp->ub_broot);
+ path = pbuf;
+ }
+
+ if ((fd = open(path, O_RDONLY)) != -1 &&
fstat(fd, &statb) != -1)
buf = libc_malloc(
statb.st_size + sizeof (auxv_t));
diff --git a/usr/src/lib/libc/port/gen/sh_locks.c b/usr/src/lib/libc/port/gen/sh_locks.c
index 6583efbc9c..cf879195c6 100644
--- a/usr/src/lib/libc/port/gen/sh_locks.c
+++ b/usr/src/lib/libc/port/gen/sh_locks.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "lint.h"
#include <mtlib.h>
#include <sys/types.h>
diff --git a/usr/src/lib/libc/port/gen/siglist.c b/usr/src/lib/libc/port/gen/siglist.c
index 441cc4c2c5..bc6dc1b731 100644
--- a/usr/src/lib/libc/port/gen/siglist.c
+++ b/usr/src/lib/libc/port/gen/siglist.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -128,6 +129,7 @@ static const char *_sys_siglist_data[NSIG] = {
"Fourteenth Realtime Signal", /* SIGRTMIN+13 */
"Fifteenth Realtime Signal", /* SIGRTMIN+14 */
"Sixteenth Realtime Signal", /* SIGRTMIN+15 */
+ "Seventeenth Realtime Signal", /* SIGRTMIN+16 */
"Sixteenth Last Realtime Signal", /* SIGRTMAX-15 */
"Fifteenth Last Realtime Signal", /* SIGRTMAX-14 */
"Fourteenth Last Realtime Signal", /* SIGRTMAX-13 */
diff --git a/usr/src/lib/libc/port/gen/str2sig.c b/usr/src/lib/libc/port/gen/str2sig.c
index e0c4e89d68..02c6f3cb65 100644
--- a/usr/src/lib/libc/port/gen/str2sig.c
+++ b/usr/src/lib/libc/port/gen/str2sig.c
@@ -22,7 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -102,6 +102,7 @@ static signame_t signames[] = {
{ "RTMIN+13", _SIGRTMIN+13 },
{ "RTMIN+14", _SIGRTMIN+14 },
{ "RTMIN+15", _SIGRTMIN+15 },
+ { "RTMIN+16", _SIGRTMIN+16 },
{ "RTMAX-15", _SIGRTMAX-15 },
{ "RTMAX-14", _SIGRTMAX-14 },
{ "RTMAX-13", _SIGRTMAX-13 },
diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc
index f547dd44da..350dfc71dd 100644
--- a/usr/src/lib/libc/port/llib-lc
+++ b/usr/src/lib/libc/port/llib-lc
@@ -25,6 +25,7 @@
* Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2013 Gary Mills
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Joyent, Inc.
* Copyright 2015 Circonus, Inc. All rights reserved.
* Copyright 2015 Joyent, Inc.
*/
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 905de27667..d70de892a1 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -3002,6 +3002,10 @@ $endif
__idmap_unreg;
__init_daemon_priv;
__init_suid_priv;
+ inotify_init;
+ inotify_init1;
+ inotify_add_watch;
+ inotify_rm_watch;
_insert;
inst_sync;
_iswctype;
@@ -3104,7 +3108,9 @@ $endif
psecflags_validate;
semctl64;
_semctl64;
+ set_escaped_context_cleanup;
set_setcontext_enforcement;
+ setcontext_sigmask;
_setbufend;
__set_errno;
setprojrctl;
@@ -3221,6 +3227,7 @@ $endif
zone_list;
zone_list_datalink;
zonept;
+ zone_get_nroot;
zone_remove_datalink;
zone_setattr;
zone_shutdown;
diff --git a/usr/src/lib/libc/port/stdio/system.c b/usr/src/lib/libc/port/stdio/system.c
index bc7e412d52..698d02b2ec 100644
--- a/usr/src/lib/libc/port/stdio/system.c
+++ b/usr/src/lib/libc/port/stdio/system.c
@@ -22,6 +22,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -43,6 +44,7 @@
#include <synch.h>
#include <spawn.h>
#include <paths.h>
+#include <zone.h>
#include "libc.h"
extern const char **_environ;
@@ -125,11 +127,18 @@ system(const char *cmd)
int error;
sigset_t mask;
struct stat64 buf;
- const char *shpath = _PATH_BSHELL;
+ char shpath[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
char *argv[4];
posix_spawnattr_t attr;
static const char *shell = "sh";
+ /*
+ * If executing in brand use native root.
+ */
+ (void) snprintf(shpath, sizeof (shpath), "%s%s",
+ zroot != NULL ? zroot : "", _PATH_BSHELL);
+
if (cmd == NULL) {
if (stat64(shpath, &buf) != 0) {
return (0);
diff --git a/usr/src/lib/libc/port/sys/epoll.c b/usr/src/lib/libc/port/sys/epoll.c
index 34cb151135..e510b0b247 100644
--- a/usr/src/lib/libc/port/sys/epoll.c
+++ b/usr/src/lib/libc/port/sys/epoll.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Joyent, Inc.
*/
#include <sys/types.h>
@@ -64,6 +64,15 @@
#define EPOLLSWIZZLED \
(EPOLLRDHUP | EPOLLONESHOT | EPOLLET | EPOLLWRBAND | EPOLLWRNORM)
+/*
+ * The defined behavior for epoll_wait/epoll_pwait when using a timeout less
+ * than 0 is to wait for events until they arrive (or interrupted by a signal).
+ * While poll(7d) operates in this manner for a timeout of -1, using other
+ * negative values results in an immediate timeout, as if it had been set to 0.
+ * For that reason, negative values are clamped to -1.
+ */
+#define EPOLL_TIMEOUT_CLAMP(t) (((t) < -1) ? -1 : (t))
+
int
epoll_create(int size)
{
@@ -209,7 +218,7 @@ epoll_wait(int epfd, struct epoll_event *events,
}
arg.dp_nfds = maxevents;
- arg.dp_timeout = timeout;
+ arg.dp_timeout = EPOLL_TIMEOUT_CLAMP(timeout);
arg.dp_fds = (pollfd_t *)events;
return (ioctl(epfd, DP_POLL, &arg));
@@ -227,7 +236,7 @@ epoll_pwait(int epfd, struct epoll_event *events,
}
arg.dp_nfds = maxevents;
- arg.dp_timeout = timeout;
+ arg.dp_timeout = EPOLL_TIMEOUT_CLAMP(timeout);
arg.dp_fds = (pollfd_t *)events;
arg.dp_setp = (sigset_t *)sigmask;
diff --git a/usr/src/lib/libc/port/sys/inotify.c b/usr/src/lib/libc/port/sys/inotify.c
new file mode 100644
index 0000000000..90d04b5dd3
--- /dev/null
+++ b/usr/src/lib/libc/port/sys/inotify.c
@@ -0,0 +1,142 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ */
+
+#include <sys/inotify.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <dirent.h>
+
+int
+inotify_init()
+{
+ return (open("/dev/inotify", O_RDWR));
+}
+
+int
+inotify_init1(int flags)
+{
+ int oflags = O_RDWR;
+
+ if (flags & IN_NONBLOCK)
+ oflags |= O_NONBLOCK;
+
+ if (flags & IN_CLOEXEC)
+ oflags |= O_CLOEXEC;
+
+ return (open("/dev/inotify", oflags));
+}
+
+int
+inotify_add_watch(int fd, const char *pathname, uint32_t mask)
+{
+ inotify_addwatch_t ioc;
+ inotify_addchild_t cioc;
+ struct stat buf;
+ int dirfd, wd;
+ DIR *dir;
+ struct dirent *dp;
+ int oflags = O_RDONLY;
+
+ if (mask & IN_DONT_FOLLOW)
+ oflags |= O_NOFOLLOW;
+
+ if ((dirfd = open(pathname, oflags)) < 0)
+ return (-1);
+
+ if (fstat(dirfd, &buf) != 0) {
+ (void) close(dirfd);
+ return (-1);
+ }
+
+ if ((mask & IN_ONLYDIR) && !(buf.st_mode & S_IFDIR)) {
+ (void) close(dirfd);
+ errno = ENOTDIR;
+ return (-1);
+ }
+
+ bzero(&ioc, sizeof (ioc));
+ ioc.inaw_fd = dirfd;
+ ioc.inaw_mask = mask;
+
+ if ((wd = ioctl(fd, INOTIFYIOC_ADD_WATCH, &ioc)) < 0) {
+ (void) close(dirfd);
+ return (-1);
+ }
+
+ if (!(buf.st_mode & S_IFDIR) || !(mask & IN_CHILD_EVENTS)) {
+ (void) close(dirfd);
+ (void) ioctl(fd, INOTIFYIOC_ACTIVATE, wd);
+ return (wd);
+ }
+
+ /*
+ * If we have a directory and we have a mask that denotes child events,
+ * we need to manually add a child watch to every directory entry.
+ * (Because our watch is in place, it will automatically be added to
+ * files that are newly created after this point.)
+ */
+ if ((dir = fdopendir(dirfd)) == NULL) {
+ (void) inotify_rm_watch(fd, wd);
+ (void) close(dirfd);
+ return (-1);
+ }
+
+ bzero(&cioc, sizeof (cioc));
+ cioc.inac_fd = dirfd;
+
+ while ((dp = readdir(dir)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0)
+ continue;
+
+ if (strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ cioc.inac_name = dp->d_name;
+
+ if (ioctl(fd, INOTIFYIOC_ADD_CHILD, &cioc) != 0) {
+ /*
+ * If we get an error that indicates clear internal
+ * malfunctioning, we propagate the error. Otherwise
+ * we eat it: this could be a file that no longer
+ * exists or a symlink or something else that we
+ * can't lookup.
+ */
+ switch (errno) {
+ case ENXIO:
+ case EFAULT:
+ case EBADF:
+ (void) closedir(dir);
+ (void) inotify_rm_watch(fd, wd);
+ return (-1);
+ default:
+ break;
+ }
+ }
+ }
+
+ (void) closedir(dir);
+ (void) ioctl(fd, INOTIFYIOC_ACTIVATE, wd);
+
+ return (wd);
+}
+
+int
+inotify_rm_watch(int fd, int wd)
+{
+ return (ioctl(fd, INOTIFYIOC_RM_WATCH, wd));
+}
diff --git a/usr/src/lib/libc/port/sys/time_util.c b/usr/src/lib/libc/port/sys/time_util.c
index 93a07aaee0..b6ea0291e2 100644
--- a/usr/src/lib/libc/port/sys/time_util.c
+++ b/usr/src/lib/libc/port/sys/time_util.c
@@ -22,10 +22,9 @@
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <time.h>
#include <errno.h>
@@ -39,6 +38,10 @@
void
hrt2ts(hrtime_t hrt, timespec_t *tsp)
{
+#if defined(__amd64)
+ tsp->tv_sec = hrt / NANOSEC;
+ tsp->tv_nsec = hrt % NANOSEC;
+#else
uint32_t sec, nsec, tmp;
tmp = (uint32_t)(hrt >> 30);
@@ -60,6 +63,7 @@ hrt2ts(hrtime_t hrt, timespec_t *tsp)
}
tsp->tv_sec = (time_t)sec;
tsp->tv_nsec = nsec;
+#endif /* defined(__amd64) */
}
/*
@@ -67,8 +71,8 @@ hrt2ts(hrtime_t hrt, timespec_t *tsp)
* All *timedwait() system call traps expect relative time.
*/
void
-abstime_to_reltime(clockid_t clock_id,
- const timespec_t *abstime, timespec_t *reltime)
+abstime_to_reltime(clockid_t clock_id, const timespec_t *abstime,
+ timespec_t *reltime)
{
extern int __clock_gettime(clockid_t, timespec_t *);
timespec_t now;
diff --git a/usr/src/lib/libc/port/sys/zone.c b/usr/src/lib/libc/port/sys/zone.c
index 4a4c70043d..8cf28c3ccf 100644
--- a/usr/src/lib/libc/port/sys/zone.c
+++ b/usr/src/lib/libc/port/sys/zone.c
@@ -22,9 +22,11 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2011 Joyent Inc. All rights reserved.
*/
#include "lint.h"
+#include "thr_uberdata.h"
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/zone.h>
@@ -39,7 +41,8 @@
zoneid_t
zone_create(const char *name, const char *root, const struct priv_set *privs,
const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz,
- int *extended_error, int match, int doi, const bslabel_t *label, int flags)
+ int *extended_error, int match, int doi, const bslabel_t *label, int flags,
+ zoneid_t req_zoneid)
{
zone_def zd;
priv_data_t *d;
@@ -59,6 +62,7 @@ zone_create(const char *name, const char *root, const struct priv_set *privs,
zd.doi = doi;
zd.label = label;
zd.flags = flags;
+ zd.zoneid = req_zoneid;
return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd));
}
@@ -241,3 +245,10 @@ zone_list_datalink(zoneid_t zoneid, int *dlnump, datalink_id_t *linkids)
{
return (syscall(SYS_zone, ZONE_LIST_DATALINK, zoneid, dlnump, linkids));
}
+
+const char *
+zone_get_nroot()
+{
+ uberdata_t *udp = curthread->ul_uberdata;
+ return (udp->ub_broot);
+}
diff --git a/usr/src/lib/libc/port/threads/sigaction.c b/usr/src/lib/libc/port/threads/sigaction.c
index 571e211f97..6a283be33b 100644
--- a/usr/src/lib/libc/port/threads/sigaction.c
+++ b/usr/src/lib/libc/port/threads/sigaction.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
*/
#include "lint.h"
@@ -284,6 +285,24 @@ take_deferred_signal(int sig)
thr_panic("take_deferred_signal(): __sigresend() failed");
}
+/*
+ * sigacthandler() attempts to clean up dangling uc_link pointers in
+ * signal handling contexts when libc believes us to have escaped
+ * a signal handler incorrectly in the past.
+ *
+ * Branded processes have a legitimate use for a chain including contexts
+ * other than those used for signal handling when tracking emulation
+ * requests from the kernel. We allow them to disable this cleanup
+ * behaviour.
+ */
+static int escaped_context_cleanup = 1;
+
+void
+set_escaped_context_cleanup(int on)
+{
+ escaped_context_cleanup = on;
+}
+
void
sigacthandler(int sig, siginfo_t *sip, void *uvp)
{
@@ -306,7 +325,7 @@ sigacthandler(int sig, siginfo_t *sip, void *uvp)
* we are actually executing at main level (self->ul_siglink == NULL).
* See the code for setjmp()/longjmp() for more details.
*/
- if (self->ul_siglink == NULL)
+ if (escaped_context_cleanup && self->ul_siglink == NULL)
ucp->uc_link = NULL;
/*
@@ -458,11 +477,12 @@ sigaction(int sig, const struct sigaction *nact, struct sigaction *oact)
}
/*
- * This is a private interface for the linux brand interface.
+ * This is a private interface for the lx brand.
*/
void
setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *),
- void (**osigacthandler)(int, siginfo_t *, void *))
+ void (**osigacthandler)(int, siginfo_t *, void *),
+ int (*brsetctxt)(const ucontext_t *))
{
ulwp_t *self = curthread;
uberdata_t *udp = self->ul_uberdata;
@@ -471,6 +491,9 @@ setsigacthandler(void (*nsigacthandler)(int, siginfo_t *, void *),
*osigacthandler = udp->sigacthandler;
udp->sigacthandler = nsigacthandler;
+
+ if (brsetctxt != NULL)
+ udp->setctxt = brsetctxt;
}
/*
@@ -517,11 +540,39 @@ set_setcontext_enforcement(int on)
setcontext_enforcement = on;
}
+/*
+ * The LX brand emulation library implements an operation that is analogous to
+ * setcontext(), but takes a different path in to the kernel. So that it can
+ * correctly restore a signal mask, we expose just the signal mask handling
+ * part of the regular setcontext() routine as a private interface.
+ */
+void
+setcontext_sigmask(ucontext_t *ucp)
+{
+ ulwp_t *self = curthread;
+
+ if (ucp->uc_flags & UC_SIGMASK) {
+ block_all_signals(self);
+ delete_reserved_signals(&ucp->uc_sigmask);
+ self->ul_sigmask = ucp->uc_sigmask;
+ if (self->ul_cursig) {
+ /*
+ * We have a deferred signal present.
+ * The signal mask will be set when the
+ * signal is taken in take_deferred_signal().
+ */
+ ASSERT(self->ul_critical + self->ul_sigdefer != 0);
+ ucp->uc_flags &= ~UC_SIGMASK;
+ }
+ }
+}
+
#pragma weak _setcontext = setcontext
int
setcontext(const ucontext_t *ucp)
{
ulwp_t *self = curthread;
+ uberdata_t *udp = self->ul_uberdata;
int ret;
ucontext_t uc;
@@ -536,20 +587,7 @@ setcontext(const ucontext_t *ucp)
/*
* Restore previous signal mask and context link.
*/
- if (uc.uc_flags & UC_SIGMASK) {
- block_all_signals(self);
- delete_reserved_signals(&uc.uc_sigmask);
- self->ul_sigmask = uc.uc_sigmask;
- if (self->ul_cursig) {
- /*
- * We have a deferred signal present.
- * The signal mask will be set when the
- * signal is taken in take_deferred_signal().
- */
- ASSERT(self->ul_critical + self->ul_sigdefer != 0);
- uc.uc_flags &= ~UC_SIGMASK;
- }
- }
+ setcontext_sigmask(&uc);
self->ul_siglink = uc.uc_link;
/*
@@ -578,7 +616,7 @@ setcontext(const ucontext_t *ucp)
*/
set_parking_flag(self, 0);
self->ul_sp = 0;
- ret = __setcontext(&uc);
+ ret = udp->setctxt(&uc);
/*
* It is OK for setcontext() to return if the user has not specified
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c
index ca667ed5e7..747e789442 100644
--- a/usr/src/lib/libc/port/threads/thr.c
+++ b/usr/src/lib/libc/port/threads/thr.c
@@ -127,6 +127,7 @@ uberdata_t __uberdata = {
0, /* ndaemons */
0, /* pid */
sigacthandler, /* sigacthandler */
+ __setcontext, /* setctxt */
NULL, /* lwp_stacks */
NULL, /* lwp_laststack */
0, /* nfreestack */
@@ -139,6 +140,7 @@ uberdata_t __uberdata = {
NULL, /* robustlocks */
NULL, /* robustlist */
NULL, /* progname */
+ NULL, /* ub_broot */
NULL, /* ub_comm_page */
NULL, /* __tdb_bootstrap */
{ /* tdb */
@@ -1233,13 +1235,19 @@ init_auxv_data(uberdata_t *udp)
{
Dl_argsinfo_t args;
+ udp->ub_broot = NULL;
udp->ub_comm_page = NULL;
if (dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args) < 0)
return;
while (args.dla_auxv->a_type != AT_NULL) {
- if (args.dla_auxv->a_type == AT_SUN_COMMPAGE) {
+ switch (args.dla_auxv->a_type) {
+ case AT_SUN_BRAND_NROOT:
+ udp->ub_broot = args.dla_auxv->a_un.a_ptr;
+ break;
+ case AT_SUN_COMMPAGE:
udp->ub_comm_page = args.dla_auxv->a_un.a_ptr;
+ break;
}
args.dla_auxv++;
}
@@ -1283,7 +1291,8 @@ libc_init(void)
/*
* Every libc, regardless of link map, needs to go through and check
* its aux vectors. Doing so will indicate whether or not this has
- * been given a comm page (to optimize certain system actions).
+ * been given a brand root (used to qualify various other data) or a
+ * comm page (to optimize certain system actions).
*/
init_auxv_data(udp);
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 8ad448f56a..e870b9fc87 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -954,6 +954,7 @@ PORTSYS= \
fcntl.o \
getpagesizes.o \
getpeerucred.o \
+ inotify.o \
inst_sync.o \
issetugid.o \
label.o \
diff --git a/usr/src/lib/libc/sparc/gen/siginfolst.c b/usr/src/lib/libc/sparc/gen/siginfolst.c
index 8451dfbb4f..8b8a1b4669 100644
--- a/usr/src/lib/libc/sparc/gen/siginfolst.c
+++ b/usr/src/lib/libc/sparc/gen/siginfolst.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -188,6 +189,7 @@ static const struct siginfolist _sys_siginfolist_data[NSIG-1] = {
0, 0,
0, 0,
0, 0, /* SIGRTMIN+15 */
+ 0, 0, /* SIGRTMIN+16 */
0, 0, /* SIGRTMAX-15 */
0, 0,
0, 0,
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index 5c131719c9..9d46f88b86 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -891,6 +891,7 @@ PORTSYS= \
chmod.o \
chown.o \
corectl.o \
+ epoll.o \
eventfd.o \
epoll.o \
exacctsys.o \
diff --git a/usr/src/lib/libc/sparcv9/gen/siginfolst.c b/usr/src/lib/libc/sparcv9/gen/siginfolst.c
index 8451dfbb4f..8b8a1b4669 100644
--- a/usr/src/lib/libc/sparcv9/gen/siginfolst.c
+++ b/usr/src/lib/libc/sparcv9/gen/siginfolst.c
@@ -22,6 +22,7 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
@@ -188,6 +189,7 @@ static const struct siginfolist _sys_siginfolist_data[NSIG-1] = {
0, 0,
0, 0,
0, 0, /* SIGRTMIN+15 */
+ 0, 0, /* SIGRTMIN+16 */
0, 0, /* SIGRTMAX-15 */
0, 0,
0, 0,
diff --git a/usr/src/lib/libctf/Makefile.com b/usr/src/lib/libctf/Makefile.com
index 4d1e01d4eb..0169c2a367 100644
--- a/usr/src/lib/libctf/Makefile.com
+++ b/usr/src/lib/libctf/Makefile.com
@@ -23,43 +23,9 @@
# Use is subject to license terms.
#
-LIBRARY = libctf.a
-VERS = .1
-
-COMMON_OBJS = \
- ctf_create.o \
- ctf_decl.o \
- ctf_error.o \
- ctf_hash.o \
- ctf_labels.o \
- ctf_lookup.o \
- ctf_open.o \
- ctf_types.o \
- ctf_util.o
-
-LIB_OBJS = \
- ctf_lib.o \
- ctf_subr.o
-
-OBJECTS = $(COMMON_OBJS) $(LIB_OBJS)
-
-include ../../Makefile.lib
+include ../Makefile.shared.com
include ../../Makefile.rootfs
-SRCS = $(COMMON_OBJS:%.o=../../../common/ctf/%.c) $(LIB_OBJS:%.o=../common/%.c)
-LIBS = $(DYNLIB) $(LINTLIB)
-
-SRCDIR = ../common
-
-CPPFLAGS += -I../common -I../../../common/ctf -DCTF_OLD_VERSIONS
-CFLAGS += $(CCVERBOSE)
-
-CERRWARN += -_gcc=-Wno-uninitialized
-
-LDLIBS += -lc
-
-$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
-
.KEEP_STATE:
all: $(LIBS)
@@ -67,7 +33,4 @@ all: $(LIBS)
lint: lintcheck
include ../../Makefile.targ
-
-objs/%.o pics/%.o: ../../../common/ctf/%.c
- $(COMPILE.c) -o $@ $<
- $(POST_PROCESS_O)
+include ../Makefile.shared.targ
diff --git a/usr/src/lib/libctf/Makefile.shared.com b/usr/src/lib/libctf/Makefile.shared.com
new file mode 100644
index 0000000000..55f090e7f8
--- /dev/null
+++ b/usr/src/lib/libctf/Makefile.shared.com
@@ -0,0 +1,90 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+#
+# This Makefile is shared between the libctf native build in tools and
+# the libctf build here for the system.
+#
+LIBRARY = libctf.a
+VERS = .1
+
+COMMON_OBJS = \
+ ctf_create.o \
+ ctf_decl.o \
+ ctf_dwarf.o \
+ ctf_error.o \
+ ctf_hash.o \
+ ctf_labels.o \
+ ctf_lookup.o \
+ ctf_open.o \
+ ctf_types.o \
+ ctf_util.o
+
+MERGEQ_OBJS = \
+ mergeq.o \
+ workq.o
+
+LIST_OBJS = \
+ list.o
+
+LIB_OBJS = \
+ ctf_convert.o \
+ ctf_elfwrite.o \
+ ctf_diff.o \
+ ctf_lib.o \
+ ctf_merge.o \
+ ctf_subr.o
+
+OBJECTS = $(COMMON_OBJS) $(LIB_OBJS) $(LIST_OBJS) $(MERGEQ_OBJS)
+MAPFILEDIR = $(SRC)/lib/libctf
+
+include $(SRC)/lib/Makefile.lib
+
+SRCS = \
+ $(COMMON_OBJS:%.o=$(SRC)/common/ctf/%.c) \
+ $(LIB_OBJS:%.o=$(SRC)/lib/libctf/common/%.c) \
+ $(LIST_OBJS:%.o=$(SRC)/common/list/%.c) \
+ $(MERGEQ_OBJS:%.o=$(SRC)/lib/mergeq/%.c)
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lelf -ldwarf -lavl
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+SRCDIR = $(SRC)/lib/libctf/common
+
+CPPFLAGS += -I$(SRC)/lib/libctf/common \
+ -I$(SRC)/common/ctf \
+ -I$(SRC)/lib/libdwarf/common \
+ -I$(SRC)/lib/mergeq \
+ -DCTF_OLD_VERSIONS
+CFLAGS += $(CCVERBOSE)
+
+CERRWARN += -_gcc=-Wno-uninitialized
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libctf/Makefile.shared.targ b/usr/src/lib/libctf/Makefile.shared.targ
new file mode 100644
index 0000000000..b6520f2366
--- /dev/null
+++ b/usr/src/lib/libctf/Makefile.shared.targ
@@ -0,0 +1,30 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
+#
+
+#
+# This Makefile is shared between both the tools and the normal library build.
+#
+
+pics/%.o: $(SRC)/common/ctf/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: $(SRC)/common/list/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: $(SRC)/lib/mergeq/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c
new file mode 100644
index 0000000000..1a433d17db
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_convert.c
@@ -0,0 +1,210 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Main conversion entry points. This has been designed such that there can be
+ * any number of different conversion backends. Currently we only have one that
+ * understands DWARFv2 (and bits of DWARFv4). Each backend should be placed in
+ * the ctf_converters list and each will be tried in turn.
+ */
+
+#include <libctf_impl.h>
+#include <gelf.h>
+
+ctf_convert_f ctf_converters[] = {
+ ctf_dwarf_convert
+};
+
+#define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f))
+
+typedef enum ctf_convert_source {
+ CTFCONV_SOURCE_NONE = 0x0,
+ CTFCONV_SOURCE_UNKNOWN = 0x01,
+ CTFCONV_SOURCE_C = 0x02,
+ CTFCONV_SOURCE_S = 0x04
+} ctf_convert_source_t;
+
+static void
+ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types)
+{
+ int i;
+ Elf_Scn *scn = NULL, *strscn;
+ *types = CTFCONV_SOURCE_NONE;
+ GElf_Shdr shdr;
+ Elf_Data *data, *strdata;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return;
+
+ if (shdr.sh_type == SHT_SYMTAB)
+ break;
+ }
+
+ if (scn == NULL)
+ return;
+
+ if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
+ return;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL)
+ return;
+
+ if ((strdata = elf_getdata(strscn, NULL)) == NULL)
+ return;
+
+ for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
+ GElf_Sym sym;
+ const char *file;
+ size_t len;
+
+ if (gelf_getsym(data, i, &sym) == NULL)
+ return;
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
+ continue;
+
+ file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
+ len = strlen(file);
+ if (len < 2 || file[len - 2] != '.') {
+ *types |= CTFCONV_SOURCE_UNKNOWN;
+ continue;
+ }
+
+ switch (file[len - 1]) {
+ case 'c':
+ *types |= CTFCONV_SOURCE_C;
+ break;
+ case 'h':
+ /* We traditionally ignore header files... */
+ break;
+ case 's':
+ *types |= CTFCONV_SOURCE_S;
+ break;
+ default:
+ *types |= CTFCONV_SOURCE_UNKNOWN;
+ break;
+ }
+ }
+}
+
+ctf_file_t *
+ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
+ int *errp, char *errbuf, size_t errlen)
+{
+ int err, i;
+ ctf_file_t *fp = NULL;
+ boolean_t notsup = B_TRUE;
+ ctf_convert_source_t type;
+
+ if (errp == NULL)
+ errp = &err;
+
+ if (elf == NULL) {
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ if (flags & ~CTF_CONVERT_F_IGNNONC) {
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ if (elf_kind(elf) != ELF_K_ELF) {
+ *errp = ECTF_FMT;
+ return (NULL);
+ }
+
+ ctf_convert_ftypes(elf, &type);
+ ctf_dprintf("got types: %d\n", type);
+ if (flags & CTF_CONVERT_F_IGNNONC) {
+ if (type == CTFCONV_SOURCE_NONE ||
+ (type & CTFCONV_SOURCE_UNKNOWN)) {
+ *errp = ECTF_CONVNOCSRC;
+ return (NULL);
+ }
+ }
+
+ for (i = 0; i < NCONVERTS; i++) {
+ ctf_conv_status_t cs;
+
+ fp = NULL;
+ cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf,
+ errlen);
+ if (cs == CTF_CONV_SUCCESS) {
+ notsup = B_FALSE;
+ break;
+ }
+ if (cs == CTF_CONV_ERROR) {
+ fp = NULL;
+ notsup = B_FALSE;
+ break;
+ }
+ }
+
+ if (notsup == B_TRUE) {
+ if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
+ (type & CTFCONV_SOURCE_C) == 0) {
+ *errp = ECTF_CONVNOCSRC;
+ return (NULL);
+ }
+ *errp = ECTF_NOCONVBKEND;
+ return (NULL);
+ }
+
+ /*
+ * Succsesful conversion.
+ */
+ if (fp != NULL) {
+ if (label == NULL)
+ label = "";
+ if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) {
+ *errp = ctf_errno(fp);
+ ctf_close(fp);
+ return (NULL);
+ }
+ if (ctf_update(fp) == CTF_ERR) {
+ *errp = ctf_errno(fp);
+ ctf_close(fp);
+ return (NULL);
+ }
+ }
+
+ return (fp);
+}
+
+ctf_file_t *
+ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp,
+ char *errbuf, size_t errlen)
+{
+ int err;
+ Elf *elf;
+ ctf_file_t *fp;
+
+ if (errp == NULL)
+ errp = &err;
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == NULL) {
+ *errp = ECTF_FMT;
+ return (NULL);
+ }
+
+ fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen);
+
+ (void) elf_end(elf);
+ return (fp);
+}
diff --git a/usr/src/lib/libctf/common/ctf_diff.c b/usr/src/lib/libctf/common/ctf_diff.c
new file mode 100644
index 0000000000..d070488bbb
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_diff.c
@@ -0,0 +1,1362 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * The following ia a basic overview of how we diff types in containers (the
+ * generally interesting part of diff, and what's used by merge). We maintain
+ * two mapping tables, a table of forward mappings (src->dest), and a reverse
+ * mapping (dest->src). Both are initialized to contain no mapping, and can also
+ * be updated to contain a negative mapping.
+ *
+ * What we do first is iterate over each type in the src container, and compare
+ * it with a type in the destination container. This may involve doing recursive
+ * comparisons -- which can involve cycles. To deal with this, whenever we
+ * encounter something which may be cyclic, we insert a guess. In other words,
+ * we assume that it may be true. This is necessary for the classic case of the
+ * following structure:
+ *
+ * struct foo {
+ * struct foo *foo_next;
+ * };
+ *
+ * If it turns out that we were wrong, we discard our guesses.
+ *
+ * If we find that a given type in src has no corresponding entry in dst, we
+ * then mark its map as CTF_ERR (-1) to indicate that it has *no* match, as
+ * opposed to the default value of 0, which indicates an unknown match.
+ * Once we've done the first iteration through src, we know at that point in
+ * time whether everything in dst is similar or not and can simply walk over it
+ * and don't have to do any additional checks.
+ */
+
+#include <libctf.h>
+#include <ctf_impl.h>
+#include <sys/debug.h>
+
+typedef struct ctf_diff_func {
+ const char *cdf_name;
+ ulong_t cdf_symidx;
+ ulong_t cdf_matchidx;
+} ctf_diff_func_t;
+
+typedef struct ctf_diff_obj {
+ const char *cdo_name;
+ ulong_t cdo_symidx;
+ ctf_id_t cdo_id;
+ ulong_t cdo_matchidx;
+} ctf_diff_obj_t;
+
+typedef struct ctf_diff_guess {
+ struct ctf_diff_guess *cdg_next;
+ ctf_id_t cdg_iid;
+ ctf_id_t cdg_oid;
+} ctf_diff_guess_t;
+
+/* typedef in libctf.h */
+struct ctf_diff {
+ uint_t cds_flags;
+ boolean_t cds_tvalid; /* types valid */
+ ctf_file_t *cds_ifp;
+ ctf_file_t *cds_ofp;
+ ctf_id_t *cds_forward;
+ ctf_id_t *cds_reverse;
+ size_t cds_fsize;
+ size_t cds_rsize;
+ ctf_diff_type_f cds_func;
+ ctf_diff_guess_t *cds_guess;
+ void *cds_arg;
+ uint_t cds_nifuncs;
+ uint_t cds_nofuncs;
+ uint_t cds_nextifunc;
+ uint_t cds_nextofunc;
+ ctf_diff_func_t *cds_ifuncs;
+ ctf_diff_func_t *cds_ofuncs;
+ boolean_t cds_ffillip;
+ boolean_t cds_fvalid;
+ uint_t cds_niobj;
+ uint_t cds_noobj;
+ uint_t cds_nextiobj;
+ uint_t cds_nextoobj;
+ ctf_diff_obj_t *cds_iobj;
+ ctf_diff_obj_t *cds_oobj;
+ boolean_t cds_ofillip;
+ boolean_t cds_ovalid;
+};
+
+#define TINDEX(tid) (tid - 1)
+
+/*
+ * Team Diff
+ */
+static int ctf_diff_type(ctf_diff_t *, ctf_file_t *, ctf_id_t, ctf_file_t *,
+ ctf_id_t);
+
+static int
+ctf_diff_name(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
+{
+ const char *iname, *oname;
+ const ctf_type_t *itp, *otp;
+
+ if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
+ return (CTF_ERR);
+
+ if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
+ return (ctf_set_errno(ifp, iid));
+
+ iname = ctf_strptr(ifp, itp->ctt_name);
+ oname = ctf_strptr(ofp, otp->ctt_name);
+
+ if ((iname == NULL || oname == NULL) && (iname != oname))
+ return (B_TRUE);
+
+ /* Two anonymous names are the same */
+ if (iname == NULL && oname == NULL)
+ return (B_FALSE);
+
+ return (strcmp(iname, oname) == 0 ? B_FALSE: B_TRUE);
+}
+
+/*
+ * For floats and ints
+ */
+static int
+ctf_diff_number(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
+{
+ ctf_encoding_t ien, den;
+
+ if (ctf_type_encoding(ifp, iid, &ien) != 0)
+ return (CTF_ERR);
+
+ if (ctf_type_encoding(ofp, oid, &den) != 0)
+ return (ctf_set_errno(ifp, iid));
+
+ if (bcmp(&ien, &den, sizeof (ctf_encoding_t)) != 0)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+/*
+ * Two typedefs are equivalent, if after we resolve a chain of typedefs, they
+ * point to equivalent types. This means that if a size_t is defined as follows:
+ *
+ * size_t -> ulong_t -> unsigned long
+ * size_t -> unsigned long
+ *
+ * That we'll ultimately end up treating them the same.
+ */
+static int
+ctf_diff_typedef(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid,
+ ctf_file_t *ofp, ctf_id_t oid)
+{
+ ctf_id_t iref = CTF_ERR, oref = CTF_ERR;
+
+ while (ctf_type_kind(ifp, iid) == CTF_K_TYPEDEF) {
+ iref = ctf_type_reference(ifp, iid);
+ if (iref == CTF_ERR)
+ return (CTF_ERR);
+ iid = iref;
+ }
+
+ while (ctf_type_kind(ofp, oid) == CTF_K_TYPEDEF) {
+ oref = ctf_type_reference(ofp, oid);
+ if (oref == CTF_ERR)
+ return (CTF_ERR);
+ oid = oref;
+ }
+
+ VERIFY(iref != CTF_ERR && oref != CTF_ERR);
+ return (ctf_diff_type(cds, ifp, iref, ofp, oref));
+}
+
+/*
+ * Two qualifiers are equivalent iff they point to two equivalent types.
+ */
+static int
+ctf_diff_qualifier(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid,
+ ctf_file_t *ofp, ctf_id_t oid)
+{
+ ctf_id_t iref, oref;
+
+ iref = ctf_type_reference(ifp, iid);
+ if (iref == CTF_ERR)
+ return (CTF_ERR);
+
+ oref = ctf_type_reference(ofp, oid);
+ if (oref == CTF_ERR)
+ return (ctf_set_errno(ifp, ctf_errno(ofp)));
+
+ return (ctf_diff_type(cds, ifp, iref, ofp, oref));
+}
+
+/*
+ * Two arrays are the same iff they have the same type for contents, the same
+ * type for the index, and the same number of elements.
+ */
+static int
+ctf_diff_array(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
+ ctf_id_t oid)
+{
+ int ret;
+ ctf_arinfo_t iar, oar;
+
+ if (ctf_array_info(ifp, iid, &iar) == CTF_ERR)
+ return (CTF_ERR);
+
+ if (ctf_array_info(ofp, oid, &oar) == CTF_ERR)
+ return (ctf_set_errno(ifp, ctf_errno(ofp)));
+
+ ret = ctf_diff_type(cds, ifp, iar.ctr_contents, ofp, oar.ctr_contents);
+ if (ret != B_FALSE)
+ return (ret);
+
+ if (iar.ctr_nelems != oar.ctr_nelems)
+ return (B_TRUE);
+
+ /*
+ * If we're ignoring integer types names, then we're trying to do a bit
+ * of a logical diff and we don't really care about the fact that the
+ * index element might not be the same here, what we care about are the
+ * number of elements and that they're the same type.
+ */
+ if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0) {
+ ret = ctf_diff_type(cds, ifp, iar.ctr_index, ofp,
+ oar.ctr_index);
+ if (ret != B_FALSE)
+ return (ret);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Two function pointers are the same if the following is all true:
+ *
+ * o They have the same return type
+ * o They have the same number of arguments
+ * o The arguments are of the same type
+ * o They have the same flags
+ */
+static int
+ctf_diff_fptr(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
+ ctf_id_t oid)
+{
+ int ret, i;
+ ctf_funcinfo_t ifunc, ofunc;
+ ctf_id_t *iids, *oids;
+
+ if (ctf_func_info_by_id(ifp, iid, &ifunc) == CTF_ERR)
+ return (CTF_ERR);
+
+ if (ctf_func_info_by_id(ofp, oid, &ofunc) == CTF_ERR)
+ return (ctf_set_errno(ifp, ctf_errno(ofp)));
+
+ if (ifunc.ctc_argc != ofunc.ctc_argc)
+ return (B_TRUE);
+
+ if (ifunc.ctc_flags != ofunc.ctc_flags)
+ return (B_TRUE);
+
+ ret = ctf_diff_type(cds, ifp, ifunc.ctc_return, ofp, ofunc.ctc_return);
+ if (ret != B_FALSE)
+ return (ret);
+
+ iids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc);
+ if (iids == NULL)
+ return (ctf_set_errno(ifp, ENOMEM));
+
+ oids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc);
+ if (oids == NULL) {
+ ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc);
+ return (ctf_set_errno(ifp, ENOMEM));
+ }
+
+ if (ctf_func_args_by_id(ifp, iid, ifunc.ctc_argc, iids) == CTF_ERR) {
+ ret = CTF_ERR;
+ goto out;
+ }
+
+ if (ctf_func_args_by_id(ofp, oid, ofunc.ctc_argc, oids) == CTF_ERR) {
+ ret = ctf_set_errno(ifp, ctf_errno(ofp));
+ goto out;
+ }
+
+ ret = B_TRUE;
+ for (i = 0; i < ifunc.ctc_argc; i++) {
+ ret = ctf_diff_type(cds, ifp, iids[i], ofp, oids[i]);
+ if (ret != B_FALSE)
+ goto out;
+ }
+ ret = B_FALSE;
+
+out:
+ ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc);
+ ctf_free(oids, sizeof (ctf_id_t) * ofunc.ctc_argc);
+ return (ret);
+}
+
+/*
+ * Two structures are the same if every member is identical to its corresponding
+ * type, at the same offset, and has the same name, as well as them having the
+ * same overall size.
+ */
+static int
+ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
+ ctf_id_t oid)
+{
+ ctf_file_t *oifp;
+ const ctf_type_t *itp, *otp;
+ ssize_t isize, iincr, osize, oincr;
+ const ctf_member_t *imp, *omp;
+ const ctf_lmember_t *ilmp, *olmp;
+ int n;
+ ctf_diff_guess_t *cdg;
+
+ oifp = ifp;
+
+ if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
+ return (CTF_ERR);
+
+ if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
+ return (ctf_set_errno(oifp, ctf_errno(ofp)));
+
+ if (ctf_type_size(ifp, iid) != ctf_type_size(ofp, oid))
+ return (B_TRUE);
+
+ if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
+ LCTF_INFO_VLEN(ofp, otp->ctt_info))
+ return (B_TRUE);
+
+ (void) ctf_get_ctt_size(ifp, itp, &isize, &iincr);
+ (void) ctf_get_ctt_size(ofp, otp, &osize, &oincr);
+
+ if (ifp->ctf_version == CTF_VERSION_1 || isize < CTF_LSTRUCT_THRESH) {
+ imp = (const ctf_member_t *)((uintptr_t)itp + iincr);
+ ilmp = NULL;
+ } else {
+ imp = NULL;
+ ilmp = (const ctf_lmember_t *)((uintptr_t)itp + iincr);
+ }
+
+ if (ofp->ctf_version == CTF_VERSION_1 || osize < CTF_LSTRUCT_THRESH) {
+ omp = (const ctf_member_t *)((uintptr_t)otp + oincr);
+ olmp = NULL;
+ } else {
+ omp = NULL;
+ olmp = (const ctf_lmember_t *)((uintptr_t)otp + oincr);
+ }
+
+ /*
+ * Insert our assumption that they're equal for the moment.
+ */
+ cdg = ctf_alloc(sizeof (ctf_diff_guess_t));
+ if (cdg == NULL)
+ return (ctf_set_errno(ifp, ENOMEM));
+ cdg->cdg_iid = iid;
+ cdg->cdg_oid = oid;
+ cdg->cdg_next = cds->cds_guess;
+ cds->cds_guess = cdg;
+ cds->cds_forward[TINDEX(iid)] = oid;
+ cds->cds_reverse[TINDEX(oid)] = iid;
+
+ for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0; n--) {
+ const char *iname, *oname;
+ ulong_t ioff, ooff;
+ ctf_id_t itype, otype;
+ int ret;
+
+ if (imp != NULL) {
+ iname = ctf_strptr(ifp, imp->ctm_name);
+ ioff = imp->ctm_offset;
+ itype = imp->ctm_type;
+ } else {
+ iname = ctf_strptr(ifp, ilmp->ctlm_name);
+ ioff = CTF_LMEM_OFFSET(ilmp);
+ itype = ilmp->ctlm_type;
+ }
+
+ if (omp != NULL) {
+ oname = ctf_strptr(ofp, omp->ctm_name);
+ ooff = omp->ctm_offset;
+ otype = omp->ctm_type;
+ } else {
+ oname = ctf_strptr(ofp, olmp->ctlm_name);
+ ooff = CTF_LMEM_OFFSET(olmp);
+ otype = olmp->ctlm_type;
+ }
+
+ if (ioff != ooff) {
+ return (B_TRUE);
+ }
+ if (strcmp(iname, oname) != 0) {
+ return (B_TRUE);
+ }
+ ret = ctf_diff_type(cds, ifp, itype, ofp, otype);
+ if (ret != B_FALSE) {
+ return (ret);
+ }
+
+ /* Advance our pointers */
+ if (imp != NULL)
+ imp++;
+ if (ilmp != NULL)
+ ilmp++;
+ if (omp != NULL)
+ omp++;
+ if (olmp != NULL)
+ olmp++;
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Two unions are the same if they have the same set of members. This is similar
+ * to, but slightly different from a struct. The offsets of members don't
+ * matter. However, their is no guarantee of ordering so we have to fall back to
+ * doing an O(N^2) scan.
+ */
+typedef struct ctf_diff_union_member {
+ ctf_diff_t *cdum_cds;
+ ctf_file_t *cdum_fp;
+ ctf_file_t *cdum_iterfp;
+ const char *cdum_name;
+ ctf_id_t cdum_type;
+ int cdum_ret;
+} ctf_diff_union_member_t;
+
+typedef struct ctf_diff_union_fp {
+ ctf_diff_t *cduf_cds;
+ ctf_file_t *cduf_curfp;
+ ctf_file_t *cduf_altfp;
+ ctf_id_t cduf_type;
+ int cduf_ret;
+} ctf_diff_union_fp_t;
+
+/* ARGSUSED */
+static int
+ctf_diff_union_check_member(const char *name, ctf_id_t id, ulong_t off,
+ void *arg)
+{
+ int ret;
+ ctf_diff_union_member_t *cdump = arg;
+
+ if (strcmp(name, cdump->cdum_name) != 0)
+ return (0);
+
+ ret = ctf_diff_type(cdump->cdum_cds, cdump->cdum_fp, cdump->cdum_type,
+ cdump->cdum_iterfp, id);
+ if (ret == CTF_ERR) {
+ cdump->cdum_ret = CTF_ERR;
+ return (1);
+ }
+
+ if (ret == B_FALSE) {
+ cdump->cdum_ret = B_FALSE;
+ /* Return non-zero to stop iteration as we have a match */
+ return (1);
+ }
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+ctf_diff_union_check_fp(const char *name, ctf_id_t id, ulong_t off, void *arg)
+{
+ int ret;
+ ctf_diff_union_member_t cdum;
+ ctf_diff_union_fp_t *cdufp = arg;
+
+ cdum.cdum_cds = cdufp->cduf_cds;
+ cdum.cdum_fp = cdufp->cduf_curfp;
+ cdum.cdum_iterfp = cdufp->cduf_altfp;
+ cdum.cdum_name = name;
+ cdum.cdum_type = id;
+ cdum.cdum_ret = B_TRUE;
+
+ ret = ctf_member_iter(cdum.cdum_iterfp, cdufp->cduf_type,
+ ctf_diff_union_check_member, &cdum);
+ if (ret == 0 || cdum.cdum_ret == CTF_ERR) {
+ /* No match found or error, terminate now */
+ cdufp->cduf_ret = cdum.cdum_ret;
+ return (1);
+ } else if (ret == CTF_ERR) {
+ (void) ctf_set_errno(cdum.cdum_fp, ctf_errno(cdum.cdum_iterfp));
+ cdufp->cduf_ret = CTF_ERR;
+ return (1);
+ } else {
+ ASSERT(cdum.cdum_ret == B_FALSE);
+ cdufp->cduf_ret = cdum.cdum_ret;
+ return (0);
+ }
+}
+
+static int
+ctf_diff_union(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
+ ctf_id_t oid)
+{
+ ctf_file_t *oifp;
+ const ctf_type_t *itp, *otp;
+ ctf_diff_union_fp_t cduf;
+ ctf_diff_guess_t *cdg;
+ int ret;
+
+ oifp = ifp;
+ if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
+ return (CTF_ERR);
+ if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
+ return (ctf_set_errno(oifp, ctf_errno(ofp)));
+
+ if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
+ LCTF_INFO_VLEN(ofp, otp->ctt_info))
+ return (B_TRUE);
+
+ cdg = ctf_alloc(sizeof (ctf_diff_guess_t));
+ if (cdg == NULL)
+ return (ctf_set_errno(ifp, ENOMEM));
+ cdg->cdg_iid = iid;
+ cdg->cdg_oid = oid;
+ cdg->cdg_next = cds->cds_guess;
+ cds->cds_guess = cdg;
+ cds->cds_forward[TINDEX(iid)] = oid;
+ cds->cds_reverse[TINDEX(oid)] = iid;
+
+ cduf.cduf_cds = cds;
+ cduf.cduf_curfp = ifp;
+ cduf.cduf_altfp = ofp;
+ cduf.cduf_type = oid;
+ cduf.cduf_ret = B_TRUE;
+ ret = ctf_member_iter(ifp, iid, ctf_diff_union_check_fp, &cduf);
+ if (ret != CTF_ERR)
+ ret = cduf.cduf_ret;
+
+ return (ret);
+}
+
+/*
+ * Two enums are equivalent if they share the same underlying type and they have
+ * the same set of members.
+ */
+static int
+ctf_diff_enum(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
+{
+ ctf_file_t *oifp;
+ const ctf_type_t *itp, *otp;
+ ssize_t iincr, oincr;
+ const ctf_enum_t *iep, *oep;
+ int n;
+
+ oifp = ifp;
+ if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
+ return (CTF_ERR);
+ if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
+ return (ctf_set_errno(oifp, ctf_errno(ofp)));
+
+ if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
+ LCTF_INFO_VLEN(ofp, otp->ctt_info))
+ return (B_TRUE);
+
+ (void) ctf_get_ctt_size(ifp, itp, NULL, &iincr);
+ (void) ctf_get_ctt_size(ofp, otp, NULL, &oincr);
+ iep = (const ctf_enum_t *)((uintptr_t)itp + iincr);
+ oep = (const ctf_enum_t *)((uintptr_t)otp + oincr);
+
+ for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0;
+ n--, iep++, oep++) {
+ if (strcmp(ctf_strptr(ifp, iep->cte_name),
+ ctf_strptr(ofp, oep->cte_name)) != 0)
+ return (B_TRUE);
+
+ if (iep->cte_value != oep->cte_value)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Two forwards are equivalent in one of two cases. If both are forwards, than
+ * they are the same. Otherwise, they're equivalent if one is a struct or union
+ * and the other is a forward.
+ */
+static int
+ctf_diff_forward(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
+{
+ int ikind, okind;
+
+ ikind = ctf_type_kind(ifp, iid);
+ okind = ctf_type_kind(ofp, oid);
+
+ if (ikind == okind) {
+ ASSERT(ikind == CTF_K_FORWARD);
+ return (B_FALSE);
+ } else if (ikind == CTF_K_FORWARD) {
+ return (okind != CTF_K_UNION && okind != CTF_K_STRUCT);
+ } else {
+ return (ikind != CTF_K_UNION && ikind != CTF_K_STRUCT);
+ }
+}
+
+/*
+ * Are two types equivalent?
+ */
+int
+ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
+ ctf_id_t oid)
+{
+ int ret, ikind, okind;
+
+ /* Do a quick short circuit */
+ if (ifp == ofp && iid == oid)
+ return (B_FALSE);
+
+ /*
+ * Check if it's something we've already encountered in a forward
+ * reference or forward negative table. Also double check the reverse
+ * table.
+ */
+ if (cds->cds_forward[TINDEX(iid)] == oid)
+ return (B_FALSE);
+ if (cds->cds_forward[TINDEX(iid)] != 0)
+ return (B_TRUE);
+ if (cds->cds_reverse[TINDEX(oid)] == iid)
+ return (B_FALSE);
+ if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0 &&
+ cds->cds_reverse[TINDEX(oid)] != 0)
+ return (B_TRUE);
+
+ ikind = ctf_type_kind(ifp, iid);
+ okind = ctf_type_kind(ofp, oid);
+
+ if (ikind != okind &&
+ ikind != CTF_K_FORWARD && okind != CTF_K_FORWARD)
+ return (B_TRUE);
+
+ /* Check names */
+ if ((ret = ctf_diff_name(ifp, iid, ofp, oid)) != B_FALSE) {
+ if (ikind != okind || ikind != CTF_K_INTEGER ||
+ (cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0)
+ return (ret);
+ }
+
+ if (ikind == CTF_K_FORWARD || okind == CTF_K_FORWARD)
+ return (ctf_diff_forward(ifp, iid, ofp, oid));
+
+ switch (ikind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ ret = ctf_diff_number(ifp, iid, ofp, oid);
+ break;
+ case CTF_K_ARRAY:
+ ret = ctf_diff_array(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_FUNCTION:
+ ret = ctf_diff_fptr(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_STRUCT:
+ ret = ctf_diff_struct(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_UNION:
+ ret = ctf_diff_union(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_ENUM:
+ ret = ctf_diff_enum(ifp, iid, ofp, oid);
+ break;
+ case CTF_K_FORWARD:
+ ret = ctf_diff_forward(ifp, iid, ofp, oid);
+ break;
+ case CTF_K_TYPEDEF:
+ ret = ctf_diff_typedef(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_POINTER:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ ret = ctf_diff_qualifier(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_UNKNOWN:
+ /*
+ * The current CTF tools use CTF_K_UNKNOWN as a padding type. We
+ * always declare two instances of CTF_K_UNKNOWN as different,
+ * even though this leads to additional diff noise.
+ */
+ ret = B_TRUE;
+ break;
+ default:
+ abort();
+ }
+
+ return (ret);
+}
+
+/*
+ * Walk every type in the first container and try to find a match in the second.
+ * If there is a match, then update both the forward and reverse mapping tables.
+ *
+ * The self variable tells us whether or not we should be comparing the input
+ * ctf container with itself or not.
+ */
+static int
+ctf_diff_pass1(ctf_diff_t *cds, boolean_t self)
+{
+ int i, j, diff;
+ int istart, iend, jstart, jend;
+
+ if (cds->cds_ifp->ctf_flags & LCTF_CHILD) {
+ istart = 0x8001;
+ iend = cds->cds_ifp->ctf_typemax + 0x8000;
+ } else {
+ istart = 1;
+ iend = cds->cds_ifp->ctf_typemax;
+ }
+
+ if (cds->cds_ofp->ctf_flags & LCTF_CHILD) {
+ jstart = 0x8001;
+ jend = cds->cds_ofp->ctf_typemax + 0x8000;
+ } else {
+ jstart = 1;
+ jend = cds->cds_ofp->ctf_typemax;
+ }
+
+ for (i = istart; i <= iend; i++) {
+ diff = B_TRUE;
+
+ /*
+ * If we're doing a self diff for dedup purposes, then we want
+ * to ensure that we compare a type i with every type in the
+ * range, [ 1, i ). Yes, this does mean that when i equals 1,
+ * we won't compare anything.
+ */
+ if (self == B_TRUE) {
+ jstart = istart;
+ jend = i - 1;
+ }
+ for (j = jstart; j <= jend; j++) {
+ ctf_diff_guess_t *cdg, *tofree;
+
+ ASSERT(cds->cds_guess == NULL);
+ diff = ctf_diff_type(cds, cds->cds_ifp, i,
+ cds->cds_ofp, j);
+ if (diff == CTF_ERR)
+ return (CTF_ERR);
+
+ /* Clean up our guesses */
+ cdg = cds->cds_guess;
+ cds->cds_guess = NULL;
+ while (cdg != NULL) {
+ if (diff == B_TRUE) {
+ cds->cds_forward[TINDEX(cdg->cdg_iid)] =
+ 0;
+ cds->cds_reverse[TINDEX(cdg->cdg_oid)] =
+ 0;
+ }
+ tofree = cdg;
+ cdg = cdg->cdg_next;
+ ctf_free(tofree, sizeof (ctf_diff_guess_t));
+ }
+
+ /* Found a hit, update the tables */
+ if (diff == B_FALSE) {
+ cds->cds_forward[TINDEX(i)] = j;
+ if (cds->cds_reverse[TINDEX(j)] == 0)
+ cds->cds_reverse[TINDEX(j)] = i;
+ break;
+ }
+ }
+
+ /* Call the callback at this point */
+ if (diff == B_TRUE) {
+ cds->cds_forward[TINDEX(i)] = CTF_ERR;
+ cds->cds_func(cds->cds_ifp, i, B_FALSE, NULL, CTF_ERR,
+ cds->cds_arg);
+ } else {
+ cds->cds_func(cds->cds_ifp, i, B_TRUE, cds->cds_ofp, j,
+ cds->cds_arg);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Now we need to walk the second container and emit anything that we didn't
+ * find as common in the first pass.
+ */
+static int
+ctf_diff_pass2(ctf_diff_t *cds)
+{
+ int i, start, end;
+
+ start = 0x1;
+ end = cds->cds_ofp->ctf_typemax;
+ if (cds->cds_ofp->ctf_flags & LCTF_CHILD) {
+ start += 0x8000;
+ end += 0x8000;
+ }
+
+ for (i = start; i <= end; i++) {
+ if (cds->cds_reverse[TINDEX(i)] != 0)
+ continue;
+ cds->cds_func(cds->cds_ofp, i, B_FALSE, NULL, CTF_ERR,
+ cds->cds_arg);
+ }
+
+ return (0);
+}
+
+int
+ctf_diff_init(ctf_file_t *ifp, ctf_file_t *ofp, ctf_diff_t **cdsp)
+{
+ ctf_diff_t *cds;
+ size_t fsize, rsize;
+
+ cds = ctf_alloc(sizeof (ctf_diff_t));
+ if (cds == NULL)
+ return (ctf_set_errno(ifp, ENOMEM));
+
+ bzero(cds, sizeof (ctf_diff_t));
+ cds->cds_ifp = ifp;
+ cds->cds_ofp = ofp;
+
+ fsize = sizeof (ctf_id_t) * ifp->ctf_typemax;
+ rsize = sizeof (ctf_id_t) * ofp->ctf_typemax;
+ if (ifp->ctf_flags & LCTF_CHILD)
+ fsize += 0x8000 * sizeof (ctf_id_t);
+ if (ofp->ctf_flags & LCTF_CHILD)
+ rsize += 0x8000 * sizeof (ctf_id_t);
+
+ cds->cds_forward = ctf_alloc(fsize);
+ if (cds->cds_forward == NULL) {
+ ctf_free(cds, sizeof (ctf_diff_t));
+ return (ctf_set_errno(ifp, ENOMEM));
+ }
+ cds->cds_fsize = fsize;
+ cds->cds_reverse = ctf_alloc(rsize);
+ if (cds->cds_reverse == NULL) {
+ ctf_free(cds->cds_forward, fsize);
+ ctf_free(cds, sizeof (ctf_diff_t));
+ return (ctf_set_errno(ifp, ENOMEM));
+ }
+ cds->cds_rsize = rsize;
+ bzero(cds->cds_forward, fsize);
+ bzero(cds->cds_reverse, rsize);
+
+ cds->cds_ifp->ctf_refcnt++;
+ cds->cds_ofp->ctf_refcnt++;
+ *cdsp = cds;
+ return (0);
+}
+
+int
+ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
+{
+ int ret;
+
+ cds->cds_func = cb;
+ cds->cds_arg = arg;
+
+ ret = ctf_diff_pass1(cds, B_FALSE);
+ if (ret == 0)
+ ret = ctf_diff_pass2(cds);
+
+ cds->cds_func = NULL;
+ cds->cds_arg = NULL;
+ cds->cds_tvalid = B_TRUE;
+ return (ret);
+}
+
+/*
+ * Do a diff where we're comparing a container with itself. In other words we'd
+ * like to know what types are actually duplicates of existing types in the
+ * container.
+ *
+ * Note this should remain private to libctf and not be exported in the public
+ * mapfile for the time being.
+ */
+int
+ctf_diff_self(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
+{
+ if (cds->cds_ifp != cds->cds_ofp)
+ return (EINVAL);
+
+ cds->cds_func = cb;
+ cds->cds_arg = arg;
+
+ return (ctf_diff_pass1(cds, B_TRUE));
+}
+
+
+void
+ctf_diff_fini(ctf_diff_t *cds)
+{
+ ctf_diff_guess_t *cdg;
+ size_t fsize, rsize;
+
+ if (cds == NULL)
+ return;
+
+ cds->cds_ifp->ctf_refcnt--;
+ cds->cds_ofp->ctf_refcnt--;
+
+ fsize = sizeof (ctf_id_t) * cds->cds_ifp->ctf_typemax;
+ rsize = sizeof (ctf_id_t) * cds->cds_ofp->ctf_typemax;
+ if (cds->cds_ifp->ctf_flags & LCTF_CHILD)
+ fsize += 0x8000 * sizeof (ctf_id_t);
+ if (cds->cds_ofp->ctf_flags & LCTF_CHILD)
+ rsize += 0x8000 * sizeof (ctf_id_t);
+
+ if (cds->cds_ifuncs != NULL)
+ ctf_free(cds->cds_ifuncs,
+ sizeof (ctf_diff_func_t) * cds->cds_nifuncs);
+ if (cds->cds_ofuncs != NULL)
+ ctf_free(cds->cds_ofuncs,
+ sizeof (ctf_diff_func_t) * cds->cds_nofuncs);
+ if (cds->cds_iobj != NULL)
+ ctf_free(cds->cds_iobj,
+ sizeof (ctf_diff_obj_t) * cds->cds_niobj);
+ if (cds->cds_oobj != NULL)
+ ctf_free(cds->cds_oobj,
+ sizeof (ctf_diff_obj_t) * cds->cds_noobj);
+ cdg = cds->cds_guess;
+ while (cdg != NULL) {
+ ctf_diff_guess_t *tofree = cdg;
+ cdg = cdg->cdg_next;
+ ctf_free(tofree, sizeof (ctf_diff_guess_t));
+ }
+ if (cds->cds_forward != NULL)
+ ctf_free(cds->cds_forward, cds->cds_fsize);
+ if (cds->cds_reverse != NULL)
+ ctf_free(cds->cds_reverse, cds->cds_rsize);
+ ctf_free(cds, sizeof (ctf_diff_t));
+}
+
+uint_t
+ctf_diff_getflags(ctf_diff_t *cds)
+{
+ return (cds->cds_flags);
+}
+
+int
+ctf_diff_setflags(ctf_diff_t *cds, uint_t flags)
+{
+ if ((flags & ~CTF_DIFF_F_IGNORE_INTNAMES) != 0)
+ return (ctf_set_errno(cds->cds_ifp, EINVAL));
+
+ cds->cds_flags = flags;
+ return (0);
+}
+
+static boolean_t
+ctf_diff_symid(ctf_diff_t *cds, ctf_id_t iid, ctf_id_t oid)
+{
+ ctf_file_t *ifp, *ofp;
+
+ ifp = cds->cds_ifp;
+ ofp = cds->cds_ofp;
+
+ /*
+ * If we have parent containers on the scene here, we need to go through
+ * and do a full diff check because while a diff for types will not
+ * actually go through and check types in the parent container.
+ */
+ if (iid == 0 || oid == 0)
+ return (iid == oid ? B_FALSE: B_TRUE);
+
+ if (!(ifp->ctf_flags & LCTF_CHILD) && !(ofp->ctf_flags & LCTF_CHILD)) {
+ if (cds->cds_forward[TINDEX(iid)] != oid)
+ return (B_TRUE);
+ return (B_FALSE);
+ }
+
+ return (ctf_diff_type(cds, ifp, iid, ofp, oid));
+}
+
+/* ARGSUSED */
+static void
+ctf_diff_void_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
+ ctf_id_t oid, void *arg)
+{
+}
+
+/* ARGSUSED */
+static int
+ctf_diff_func_count(const char *name, ulong_t symidx, ctf_funcinfo_t *fip,
+ void *arg)
+{
+ uint32_t *ip = arg;
+
+ *ip = *ip + 1;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+ctf_diff_func_fill_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *fip,
+ void *arg)
+{
+ uint_t *next, max;
+ ctf_diff_func_t *funcptr;
+ ctf_diff_t *cds = arg;
+
+ if (cds->cds_ffillip == B_TRUE) {
+ max = cds->cds_nifuncs;
+ next = &cds->cds_nextifunc;
+ funcptr = cds->cds_ifuncs + *next;
+ } else {
+ max = cds->cds_nofuncs;
+ next = &cds->cds_nextofunc;
+ funcptr = cds->cds_ofuncs + *next;
+
+ }
+
+ VERIFY(*next < max);
+ funcptr->cdf_name = name;
+ funcptr->cdf_symidx = symidx;
+ funcptr->cdf_matchidx = ULONG_MAX;
+ *next = *next + 1;
+
+ return (0);
+}
+
+int
+ctf_diff_func_fill(ctf_diff_t *cds)
+{
+ int ret;
+ uint32_t ifcount, ofcount, idcnt, cti;
+ ulong_t i, j;
+ ctf_id_t *iids, *oids;
+
+ ifcount = 0;
+ ofcount = 0;
+ idcnt = 0;
+ iids = NULL;
+ oids = NULL;
+
+ ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_count, &ifcount);
+ if (ret != 0)
+ return (ret);
+ ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_count, &ofcount);
+ if (ret != 0)
+ return (ret);
+
+ cds->cds_ifuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ifcount);
+ if (cds->cds_ifuncs == NULL)
+ return (ctf_set_errno(cds->cds_ifp, ENOMEM));
+
+ cds->cds_nifuncs = ifcount;
+ cds->cds_nextifunc = 0;
+
+ cds->cds_ofuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ofcount);
+ if (cds->cds_ofuncs == NULL)
+ return (ctf_set_errno(cds->cds_ifp, ENOMEM));
+
+ cds->cds_nofuncs = ofcount;
+ cds->cds_nextofunc = 0;
+
+ cds->cds_ffillip = B_TRUE;
+ if ((ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_fill_cb,
+ cds)) != 0)
+ return (ret);
+
+ cds->cds_ffillip = B_FALSE;
+ if ((ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_fill_cb,
+ cds)) != 0)
+ return (ret);
+
+ /*
+ * Everything is initialized to not match. This could probably be faster
+ * with something that used a hash. But this part of the diff isn't used
+ * by merge.
+ */
+ for (i = 0; i < cds->cds_nifuncs; i++) {
+ for (j = 0; j < cds->cds_nofuncs; j++) {
+ ctf_diff_func_t *ifd, *ofd;
+ ctf_funcinfo_t ifip, ofip;
+ boolean_t match;
+
+ ifd = &cds->cds_ifuncs[i];
+ ofd = &cds->cds_ofuncs[j];
+ if (strcmp(ifd->cdf_name, ofd->cdf_name) != 0)
+ continue;
+
+ ret = ctf_func_info(cds->cds_ifp, ifd->cdf_symidx,
+ &ifip);
+ if (ret != 0)
+ goto out;
+ ret = ctf_func_info(cds->cds_ofp, ofd->cdf_symidx,
+ &ofip);
+ if (ret != 0) {
+ ret = ctf_set_errno(cds->cds_ifp,
+ ctf_errno(cds->cds_ofp));
+ goto out;
+ }
+
+ if (ifip.ctc_argc != ofip.ctc_argc &&
+ ifip.ctc_flags != ofip.ctc_flags)
+ continue;
+
+ /* Validate return type and arguments are the same */
+ if (ctf_diff_symid(cds, ifip.ctc_return,
+ ofip.ctc_return))
+ continue;
+
+ if (ifip.ctc_argc > idcnt) {
+ if (iids != NULL)
+ ctf_free(iids,
+ sizeof (ctf_id_t) * idcnt);
+ if (oids != NULL)
+ ctf_free(oids,
+ sizeof (ctf_id_t) * idcnt);
+ iids = oids = NULL;
+ idcnt = ifip.ctc_argc;
+ iids = ctf_alloc(sizeof (ctf_id_t) * idcnt);
+ if (iids == NULL) {
+ ret = ctf_set_errno(cds->cds_ifp,
+ ENOMEM);
+ goto out;
+ }
+ oids = ctf_alloc(sizeof (ctf_id_t) * idcnt);
+ if (iids == NULL) {
+ ret = ctf_set_errno(cds->cds_ifp,
+ ENOMEM);
+ goto out;
+ }
+ }
+
+ if ((ret = ctf_func_args(cds->cds_ifp, ifd->cdf_symidx,
+ ifip.ctc_argc, iids)) != 0)
+ goto out;
+ if ((ret = ctf_func_args(cds->cds_ofp, ofd->cdf_symidx,
+ ofip.ctc_argc, oids)) != 0)
+ goto out;
+
+ match = B_TRUE;
+ for (cti = 0; cti < ifip.ctc_argc; cti++) {
+ if (ctf_diff_symid(cds, iids[cti], oids[cti])) {
+ match = B_FALSE;
+ break;
+ }
+ }
+
+ if (match == B_FALSE)
+ continue;
+
+ ifd->cdf_matchidx = j;
+ ofd->cdf_matchidx = i;
+ break;
+ }
+ }
+
+ ret = 0;
+
+out:
+ if (iids != NULL)
+ ctf_free(iids, sizeof (ctf_id_t) * idcnt);
+ if (oids != NULL)
+ ctf_free(oids, sizeof (ctf_id_t) * idcnt);
+
+ return (ret);
+}
+
+/*
+ * In general, two functions are the same, if they have the same name and their
+ * arguments have the same types, including the return type. Like types, we
+ * basically have to do this in two passes. In the first phase we walk every
+ * type in the first container and try to find a match in the second.
+ */
+int
+ctf_diff_functions(ctf_diff_t *cds, ctf_diff_func_f cb, void *arg)
+{
+ int ret;
+ ulong_t i;
+
+ if (cds->cds_tvalid == B_FALSE) {
+ if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0)
+ return (ret);
+ }
+
+ if (cds->cds_fvalid == B_FALSE) {
+ if ((ret = ctf_diff_func_fill(cds)) != 0)
+ return (ret);
+ cds->cds_fvalid = B_TRUE;
+ }
+
+ for (i = 0; i < cds->cds_nifuncs; i++) {
+ if (cds->cds_ifuncs[i].cdf_matchidx == ULONG_MAX) {
+ cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx,
+ B_FALSE, NULL, ULONG_MAX, arg);
+ } else {
+ ulong_t idx = cds->cds_ifuncs[i].cdf_matchidx;
+ cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx, B_TRUE,
+ cds->cds_ofp, cds->cds_ofuncs[idx].cdf_symidx, arg);
+ }
+ }
+
+ for (i = 0; i < cds->cds_nofuncs; i++) {
+ if (cds->cds_ofuncs[i].cdf_matchidx != ULONG_MAX)
+ continue;
+ cb(cds->cds_ofp, cds->cds_ofuncs[i].cdf_symidx, B_FALSE,
+ NULL, ULONG_MAX, arg);
+ }
+
+ return (0);
+}
+
+static int
+ctf_diff_obj_fill_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
+{
+ uint_t *next, max;
+ ctf_diff_obj_t *objptr;
+ ctf_diff_t *cds = arg;
+
+ if (cds->cds_ofillip == B_TRUE) {
+ max = cds->cds_niobj;
+ next = &cds->cds_nextiobj;
+ objptr = cds->cds_iobj + *next;
+ } else {
+ max = cds->cds_noobj;
+ next = &cds->cds_nextoobj;
+ objptr = cds->cds_oobj+ *next;
+
+ }
+
+ VERIFY(*next < max);
+ objptr->cdo_name = name;
+ objptr->cdo_symidx = symidx;
+ objptr->cdo_id = id;
+ objptr->cdo_matchidx = ULONG_MAX;
+ *next = *next + 1;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+ctf_diff_obj_count(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
+{
+ uint32_t *count = arg;
+
+ *count = *count + 1;
+
+ return (0);
+}
+
+
+static int
+ctf_diff_obj_fill(ctf_diff_t *cds)
+{
+ int ret;
+ uint32_t iocount, oocount;
+ ulong_t i, j;
+
+ iocount = 0;
+ oocount = 0;
+
+ ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_count, &iocount);
+ if (ret != 0)
+ return (ret);
+
+ ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_count, &oocount);
+ if (ret != 0)
+ return (ret);
+
+ cds->cds_iobj = ctf_alloc(sizeof (ctf_diff_obj_t) * iocount);
+ if (cds->cds_iobj == NULL)
+ return (ctf_set_errno(cds->cds_ifp, ENOMEM));
+ cds->cds_niobj = iocount;
+ cds->cds_nextiobj = 0;
+
+ cds->cds_oobj = ctf_alloc(sizeof (ctf_diff_obj_t) * oocount);
+ if (cds->cds_oobj == NULL)
+ return (ctf_set_errno(cds->cds_ifp, ENOMEM));
+ cds->cds_noobj = oocount;
+ cds->cds_nextoobj = 0;
+
+ cds->cds_ofillip = B_TRUE;
+ if ((ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_fill_cb,
+ cds)) != 0)
+ return (ret);
+
+ cds->cds_ofillip = B_FALSE;
+ if ((ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_fill_cb,
+ cds)) != 0)
+ return (ret);
+
+ for (i = 0; i < cds->cds_niobj; i++) {
+ for (j = 0; j < cds->cds_noobj; j++) {
+ ctf_diff_obj_t *id, *od;
+
+ id = &cds->cds_iobj[i];
+ od = &cds->cds_oobj[j];
+
+ if (id->cdo_name == NULL || od->cdo_name == NULL)
+ continue;
+ if (strcmp(id->cdo_name, od->cdo_name) != 0)
+ continue;
+
+ if (ctf_diff_symid(cds, id->cdo_id, od->cdo_id)) {
+ continue;
+ }
+
+ id->cdo_matchidx = j;
+ od->cdo_matchidx = i;
+ break;
+ }
+ }
+
+ return (0);
+}
+
+int
+ctf_diff_objects(ctf_diff_t *cds, ctf_diff_obj_f cb, void *arg)
+{
+ int ret;
+ ulong_t i;
+
+ if (cds->cds_tvalid == B_FALSE) {
+ if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0)
+ return (ret);
+ }
+
+ if (cds->cds_ovalid == B_FALSE) {
+ if ((ret = ctf_diff_obj_fill(cds)) != 0)
+ return (ret);
+ cds->cds_ovalid = B_TRUE;
+ }
+
+ for (i = 0; i < cds->cds_niobj; i++) {
+ ctf_diff_obj_t *o = &cds->cds_iobj[i];
+
+ if (cds->cds_iobj[i].cdo_matchidx == ULONG_MAX) {
+ cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_FALSE,
+ NULL, ULONG_MAX, CTF_ERR, arg);
+ } else {
+ ctf_diff_obj_t *alt = &cds->cds_oobj[o->cdo_matchidx];
+ cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_TRUE,
+ cds->cds_ofp, alt->cdo_symidx, alt->cdo_id, arg);
+ }
+ }
+
+ for (i = 0; i < cds->cds_noobj; i++) {
+ ctf_diff_obj_t *o = &cds->cds_oobj[i];
+ if (o->cdo_matchidx != ULONG_MAX)
+ continue;
+ cb(cds->cds_ofp, o->cdo_symidx, o->cdo_id, B_FALSE, NULL,
+ ULONG_MAX, CTF_ERR, arg);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
new file mode 100644
index 0000000000..811a55bc64
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -0,0 +1,2957 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2012 Jason King. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * CTF DWARF conversion theory.
+ *
+ * DWARF data contains a series of compilation units. Each compilation unit
+ * generally refers to an object file or what once was, in the case of linked
+ * binaries and shared objects. Each compilation unit has a series of what DWARF
+ * calls a DIE (Debugging Information Entry). The set of entries that we care
+ * about have type information stored in a series of attributes. Each DIE also
+ * has a tag that identifies the kind of attributes that it has.
+ *
+ * A given DIE may itself have children. For example, a DIE that represents a
+ * structure has children which represent members. Whenever we encounter a DIE
+ * that has children or other values or types associated with it, we recursively
+ * process those children first so that way we can then refer to the generated
+ * CTF type id while processing its parent. This reduces the amount of unknowns
+ * and fixups that we need. It also ensures that we don't accidentally add types
+ * that an overzealous compiler might add to the DWARF data but aren't used by
+ * anything in the system.
+ *
+ * Once we do a conversion, we store a mapping in an AVL tree that goes from the
+ * DWARF's die offset, which is relative to the given compilation unit), to a
+ * ctf_id_t.
+ *
+ * Unfortunately, some compilers actually will emit duplicate entries for a
+ * given type that look similar, but aren't quite. To that end, we go through
+ * and do a variant on a merge once we're done processing a single compilation
+ * unit which deduplicates all of the types that are in the unit.
+ *
+ * Finally, if we encounter an object that has multiple compilation units, then
+ * we'll convert all of the compilation units separately and then do a merge, so
+ * that way we can result in one single ctf_file_t that represents everything
+ * for the object.
+ *
+ * Conversion Steps
+ * ----------------
+ *
+ * Because a given object we've been given to convert may have multiple
+ * compilation units, we break the work into two halves. The first half
+ * processes each compilation unit (potentially in parallel) and then the second
+ * half optionally merges all of the dies in the first half. First, we'll cover
+ * what's involved in converting a single ctf_die_t's dwarf to CTF. This covers
+ * the work done in ctf_dwarf_convert_one().
+ *
+ * An individual ctf_die_t, which represents a compilation unit, is converted to
+ * CTF in a series of multiple passes.
+ *
+ * Pass 1: During the first pass we walk all of the dies and if we find a
+ * function, variable, struct, union, enum or typedef, we recursively transform
+ * all of its types. We don't recurse or process everything, because we don't
+ * want to add some of the types that compilers may add which are effectively
+ * unused.
+ *
+ * During pass 1, if we encounter any structures or unions we mark them for
+ * fixing up later. This is necessary because we may not be able to determine
+ * the full size of a structure at the beginning of time. This will happen if
+ * the DWARF attribute DW_AT_byte_size is not present for a member. Because of
+ * this possibility we defer adding members to structures or even converting
+ * them during pass 1 and save that for pass 2. Adding all of the base
+ * structures without any of their members helps deal with any circular
+ * dependencies that we might encounter.
+ *
+ * Pass 2: This pass is used to do the first half of fixing up structures and
+ * unions. Rather than walk the entire type space again, we actually walk the
+ * list of structures and unions that we marked for later fixing up. Here, we
+ * iterate over every structure and add members to the underlying ctf_file_t,
+ * but not to the structs themselves. One might wonder why we don't, and the
+ * main reason is that libctf requires a ctf_update() be done before adding the
+ * members to structures or unions.
+ *
+ * Pass 3: This pass is used to do the second half of fixing up structures and
+ * unions. During this part we always go through and add members to structures
+ * and unions that we added to the container in the previous pass. In addition,
+ * we set the structure and union's actual size, which may have additional
+ * padding added by the compiler, it isn't simply the last offset. DWARF always
+ * guarantees an attribute exists for this. Importantly no ctf_id_t's change
+ * during pass 2.
+ *
+ * Pass 4: The next phase is to add CTF entries for all of the symbols and
+ * variables that are present in this die. During pass 1 we added entries to a
+ * map for each variable and function. During this pass, we iterate over the
+ * symbol table and when we encounter a symbol that we have in our lists of
+ * translated information which matches, we then add it to the ctf_file_t.
+ *
+ * Pass 5: Here we go and look for any weak symbols and functions and see if
+ * they match anything that we recognize. If so, then we add type information
+ * for them at this point based on the matching type.
+ *
+ * Pass 6: This pass is actually a variant on a merge. The traditional merge
+ * process expects there to be no duplicate types. As such, at the end of
+ * conversion, we do a dedup on all of the types in the system. The
+ * deduplication process is described in lib/libctf/common/ctf_merge.c.
+ *
+ * Once pass 6 is done, we've finished processing the individual compilation
+ * unit.
+ *
+ * The following steps reflect the general process of doing a conversion.
+ *
+ * 1) Walk the dwarf section and determine the number of compilation units
+ * 2) Create a ctf_die_t for each compilation unit
+ * 3) Add all ctf_die_t's to a workq
+ * 4) Have the workq process each die with ctf_dwarf_convert_one. This itself
+ * is comprised of several steps, which were already enumerated.
+ * 5) If we have multiple dies, we do a ctf merge of all the dies. The mechanics
+ * of the merge are discussed in lib/libctf/common/ctf_merge.c.
+ * 6) Free everything up and return a ctf_file_t to the user. If we only had a
+ * single compilation unit, then we give that to the user. Otherwise, we
+ * return the merged ctf_file_t.
+ *
+ * Threading
+ * ---------
+ *
+ * The process has been designed to be amenable to threading. Each compilation
+ * unit has its own type stream, therefore the logical place to divide and
+ * conquer is at the compilation unit. Each ctf_die_t has been built to be able
+ * to be processed independently of the others. It has its own libdwarf handle,
+ * as a given libdwarf handle may only be used by a single thread at a time.
+ * This allows the various ctf_die_t's to be processed in parallel by different
+ * threads.
+ *
+ * All of the ctf_die_t's are loaded into a workq which allows for a number of
+ * threads to be specified and used as a thread pool to process all of the
+ * queued work. We set the number of threads to use in the workq equal to the
+ * number of threads that the user has specified.
+ *
+ * After all of the compilation units have been drained, we use the same number
+ * of threads when performing a merge of multiple compilation units, if they
+ * exist.
+ *
+ * While all of these different parts do support and allow for multiple threads,
+ * it's important that when only a single thread is specified, that it be the
+ * calling thread. This allows the conversion routines to be used in a context
+ * that doesn't allow additional threads, such as rtld.
+ *
+ * Common DWARF Mechanics and Notes
+ * --------------------------------
+ *
+ * At this time, we really only support DWARFv2, though support for DWARFv4 is
+ * mostly there. There is no intent to support DWARFv3.
+ *
+ * Generally types for something are stored in the DW_AT_type attribute. For
+ * example, a function's return type will be stored in the local DW_AT_type
+ * attribute while the arguments will be in child DIEs. There are also various
+ * times when we don't have any DW_AT_type. In that case, the lack of a type
+ * implies, at least for C, that it's C type is void. Because DWARF doesn't emit
+ * one, we have a synthetic void type that we create and manipulate instead and
+ * pass it off to consumers on an as-needed basis. If nothing has a void type,
+ * it will not be emitted.
+ *
+ * Architecture Specific Parts
+ * ---------------------------
+ *
+ * The CTF tooling encodes various information about the various architectures
+ * in the system. Importantly, the tool assumes that every architecture has a
+ * data model where long and pointer are the same size. This is currently the
+ * case, as the two data models illumos supports are ILP32 and LP64.
+ *
+ * In addition, we encode the mapping of various floating point sizes to various
+ * types for each architecture. If a new architecture is being added, it should
+ * be added to the list. The general design of the ctf conversion tools is to be
+ * architecture independent. eg. any of the tools here should be able to convert
+ * any architecture's DWARF into ctf; however, this has not been rigorously
+ * tested and more importantly, the ctf routines don't currently write out the
+ * data in an endian-aware form, they only use that of the currently running
+ * library.
+ */
+
+#include <libctf_impl.h>
+#include <sys/avl.h>
+#include <sys/debug.h>
+#include <gelf.h>
+#include <libdwarf.h>
+#include <dwarf.h>
+#include <libgen.h>
+#include <workq.h>
+#include <errno.h>
+
+#define DWARF_VERSION_TWO 2
+#define DWARF_VARARGS_NAME "..."
+
+/*
+ * Dwarf may refer recursively to other types that we've already processed. To
+ * see if we've already converted them, we look them up in an AVL tree that's
+ * sorted by the DWARF id.
+ */
+typedef struct ctf_dwmap {
+ avl_node_t cdm_avl;
+ Dwarf_Off cdm_off;
+ Dwarf_Die cdm_die;
+ ctf_id_t cdm_id;
+ boolean_t cdm_fix;
+} ctf_dwmap_t;
+
+typedef struct ctf_dwvar {
+ ctf_list_t cdv_list;
+ char *cdv_name;
+ ctf_id_t cdv_type;
+ boolean_t cdv_global;
+} ctf_dwvar_t;
+
+typedef struct ctf_dwfunc {
+ ctf_list_t cdf_list;
+ char *cdf_name;
+ ctf_funcinfo_t cdf_fip;
+ ctf_id_t *cdf_argv;
+ boolean_t cdf_global;
+} ctf_dwfunc_t;
+
+typedef struct ctf_dwbitf {
+ ctf_list_t cdb_list;
+ ctf_id_t cdb_base;
+ uint_t cdb_nbits;
+ ctf_id_t cdb_id;
+} ctf_dwbitf_t;
+
+/*
+ * The ctf_die_t represents a single top-level DWARF die unit. While generally,
+ * the typical object file hs only a single die, if we're asked to convert
+ * something that's been linked from multiple sources, multiple dies will exist.
+ */
+typedef struct ctf_die {
+ Elf *cd_elf; /* shared libelf handle */
+ char *cd_name; /* basename of the DIE */
+ ctf_merge_t *cd_cmh; /* merge handle */
+ ctf_list_t cd_vars; /* List of variables */
+ ctf_list_t cd_funcs; /* List of functions */
+ ctf_list_t cd_bitfields; /* Bit field members */
+ Dwarf_Debug cd_dwarf; /* shared libdwarf handle */
+ Dwarf_Die cd_cu; /* libdwarf compilation unit */
+ Dwarf_Off cd_cuoff; /* cu's offset */
+ Dwarf_Off cd_maxoff; /* maximum offset */
+ ctf_file_t *cd_ctfp; /* output CTF file */
+ avl_tree_t cd_map; /* map die offsets to CTF types */
+ char *cd_errbuf; /* error message buffer */
+ size_t cd_errlen; /* error message buffer length */
+ size_t cd_ptrsz; /* object's pointer size */
+ boolean_t cd_bigend; /* is it big endian */
+ boolean_t cd_doweaks; /* should we convert weak symbols? */
+ uint_t cd_mach; /* machine type */
+ ctf_id_t cd_voidtid; /* void pointer */
+ ctf_id_t cd_longtid; /* id for a 'long' */
+} ctf_die_t;
+
+static int ctf_dwarf_offset(ctf_die_t *, Dwarf_Die, Dwarf_Off *);
+static int ctf_dwarf_convert_die(ctf_die_t *, Dwarf_Die);
+static int ctf_dwarf_convert_type(ctf_die_t *, Dwarf_Die, ctf_id_t *, int);
+
+static int ctf_dwarf_function_count(ctf_die_t *, Dwarf_Die, ctf_funcinfo_t *,
+ boolean_t);
+static int ctf_dwarf_convert_fargs(ctf_die_t *, Dwarf_Die, ctf_funcinfo_t *,
+ ctf_id_t *);
+
+typedef int (ctf_dwarf_symtab_f)(ctf_die_t *, const GElf_Sym *, ulong_t,
+ const char *, const char *, void *);
+
+/*
+ * This is a generic way to set a CTF Conversion backend error depending on what
+ * we were doing. Unless it was one of a specific set of errors that don't
+ * indicate a programming / translation bug, eg. ENOMEM, then we transform it
+ * into a CTF backend error and fill in the error buffer.
+ */
+static int
+ctf_dwarf_error(ctf_die_t *cdp, ctf_file_t *cfp, int err, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ size_t off = 0;
+ ssize_t rem = cdp->cd_errlen;
+ if (cfp != NULL)
+ err = ctf_errno(cfp);
+
+ if (err == ENOMEM)
+ return (err);
+
+ ret = snprintf(cdp->cd_errbuf, rem, "die %s: ", cdp->cd_name);
+ if (ret < 0)
+ goto err;
+ off += ret;
+ rem = MAX(rem - ret, 0);
+
+ va_start(ap, fmt);
+ ret = vsnprintf(cdp->cd_errbuf + off, rem, fmt, ap);
+ va_end(ap);
+ if (ret < 0)
+ goto err;
+
+ off += ret;
+ rem = MAX(rem - ret, 0);
+ if (fmt[strlen(fmt) - 1] != '\n') {
+ (void) snprintf(cdp->cd_errbuf + off, rem,
+ ": %s\n", ctf_errmsg(err));
+ }
+ va_end(ap);
+ return (ECTF_CONVBKERR);
+
+err:
+ cdp->cd_errbuf[0] = '\0';
+ return (ECTF_CONVBKERR);
+}
+
+/*
+ * DWARF often ops to put no explicit type to describe a void type. eg. if we
+ * have a reference type whose DW_AT_type member doesn't exist, then we should
+ * instead assume it points to void. Because this isn't represented, we
+ * instead cause it to come into existence.
+ */
+static ctf_id_t
+ctf_dwarf_void(ctf_die_t *cdp)
+{
+ if (cdp->cd_voidtid == CTF_ERR) {
+ ctf_encoding_t enc = { CTF_INT_SIGNED, 0, 0 };
+ cdp->cd_voidtid = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_ROOT,
+ "void", &enc);
+ if (cdp->cd_voidtid == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to create void type: %s\n",
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ }
+ }
+
+ return (cdp->cd_voidtid);
+}
+
+/*
+ * There are many different forms that an array index may take. However, we just
+ * always force it to be of a type long no matter what. Therefore we use this to
+ * have a single instance of long across everything.
+ */
+static ctf_id_t
+ctf_dwarf_long(ctf_die_t *cdp)
+{
+ if (cdp->cd_longtid == CTF_ERR) {
+ ctf_encoding_t enc;
+
+ enc.cte_format = CTF_INT_SIGNED;
+ enc.cte_offset = 0;
+ /* All illumos systems are LP */
+ enc.cte_bits = cdp->cd_ptrsz * 8;
+ cdp->cd_longtid = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_NONROOT,
+ "long", &enc);
+ if (cdp->cd_longtid == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to create long type: %s\n",
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ }
+
+ }
+
+ return (cdp->cd_longtid);
+}
+
+static int
+ctf_dwmap_comp(const void *a, const void *b)
+{
+ const ctf_dwmap_t *ca = a;
+ const ctf_dwmap_t *cb = b;
+
+ if (ca->cdm_off > cb->cdm_off)
+ return (1);
+ if (ca->cdm_off < cb->cdm_off)
+ return (-1);
+ return (0);
+}
+
+static int
+ctf_dwmap_add(ctf_die_t *cdp, ctf_id_t id, Dwarf_Die die, boolean_t fix)
+{
+ int ret;
+ avl_index_t index;
+ ctf_dwmap_t *dwmap;
+ Dwarf_Off off;
+
+ VERIFY(id > 0 && id < CTF_MAX_TYPE);
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &off)) != 0)
+ return (ret);
+
+ if ((dwmap = ctf_alloc(sizeof (ctf_dwmap_t))) == NULL)
+ return (ENOMEM);
+
+ dwmap->cdm_die = die;
+ dwmap->cdm_off = off;
+ dwmap->cdm_id = id;
+ dwmap->cdm_fix = fix;
+
+ ctf_dprintf("dwmap: %p %x->%d\n", dwmap, (uint32_t)off, id);
+ VERIFY(avl_find(&cdp->cd_map, dwmap, &index) == NULL);
+ avl_insert(&cdp->cd_map, dwmap, index);
+ return (0);
+}
+
+static int
+ctf_dwarf_attribute(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Attribute *attrp)
+{
+ int ret;
+ Dwarf_Error derr;
+
+ if ((ret = dwarf_attr(die, name, attrp, &derr)) == DW_DLV_OK)
+ return (0);
+ if (ret == DW_DLV_NO_ENTRY) {
+ *attrp = NULL;
+ return (ENOENT);
+ }
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_ref(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formref(attr, refp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_refdie(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Die *diep)
+{
+ int ret;
+ Dwarf_Off off;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_ref(cdp, die, DW_AT_type, &off)) != 0)
+ return (ret);
+
+ off += cdp->cd_cuoff;
+ if ((ret = dwarf_offdie(cdp->cd_dwarf, off, diep, &derr)) !=
+ DW_DLV_OK) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get die from offset %llu: %s\n",
+ off, dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_signed(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Signed *valp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formsdata(attr, valp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_unsigned(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Unsigned *valp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_boolean(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Bool *val)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formflag(attr, val, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get boolean attribute for type: %s\n",
+ dwarf_errmsg(derr));
+
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_string(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name, char **strp)
+{
+ int ret;
+ char *s;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ *strp = NULL;
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formstring(attr, &s, &derr) == DW_DLV_OK) {
+ if ((*strp = ctf_strdup(s)) == NULL)
+ ret = ENOMEM;
+ else
+ ret = 0;
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (ret);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get string attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_member_location(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Unsigned *valp)
+{
+ int ret;
+ Dwarf_Error derr;
+ Dwarf_Attribute attr;
+ Dwarf_Locdesc *loc;
+ Dwarf_Signed locnum;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, DW_AT_data_member_location,
+ &attr)) != 0)
+ return (ret);
+
+ if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to obtain location list for member offset: %s",
+ dwarf_errmsg(derr));
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (ECTF_CONVBKERR);
+ }
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+
+ if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to parse location structure for member");
+ dwarf_dealloc(cdp->cd_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(cdp->cd_dwarf, loc, DW_DLA_LOCDESC);
+ return (ECTF_CONVBKERR);
+ }
+
+ *valp = loc->ld_s->lr_number;
+
+ dwarf_dealloc(cdp->cd_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(cdp->cd_dwarf, loc, DW_DLA_LOCDESC);
+ return (0);
+}
+
+
+static int
+ctf_dwarf_offset(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Off *offsetp)
+{
+ Dwarf_Error derr;
+
+ if (dwarf_dieoffset(die, offsetp, &derr) == DW_DLV_OK)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get die offset: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_tag(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half *tagp)
+{
+ Dwarf_Error derr;
+
+ if (dwarf_tag(die, tagp, &derr) == DW_DLV_OK)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get tag type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_sib(ctf_die_t *cdp, Dwarf_Die base, Dwarf_Die *sibp)
+{
+ Dwarf_Error derr;
+ int ret;
+
+ *sibp = NULL;
+ ret = dwarf_siblingof(cdp->cd_dwarf, base, sibp, &derr);
+ if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to sibling from die: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_child(ctf_die_t *cdp, Dwarf_Die base, Dwarf_Die *childp)
+{
+ Dwarf_Error derr;
+ int ret;
+
+ *childp = NULL;
+ ret = dwarf_child(base, childp, &derr);
+ if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to child from die: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+/*
+ * Compilers disagree on what to do to determine if something has global
+ * visiblity. Traditionally gcc has used DW_AT_external to indicate this while
+ * Studio has used DW_AT_visibility. We check DW_AT_visibility first and then
+ * fall back to DW_AT_external. Lack of DW_AT_external implies that it is not.
+ */
+static int
+ctf_dwarf_isglobal(ctf_die_t *cdp, Dwarf_Die die, boolean_t *igp)
+{
+ int ret;
+ Dwarf_Signed vis;
+ Dwarf_Bool ext;
+
+ if ((ret = ctf_dwarf_signed(cdp, die, DW_AT_visibility, &vis)) == 0) {
+ *igp = vis == DW_VIS_exported;
+ return (0);
+ } else if (ret != ENOENT) {
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_external, &ext)) != 0) {
+ if (ret == ENOENT) {
+ *igp = B_FALSE;
+ return (0);
+ }
+ return (ret);
+ }
+ *igp = ext != 0 ? B_TRUE : B_FALSE;
+ return (0);
+}
+
+static int
+ctf_dwarf_die_elfenc(Elf *elf, ctf_die_t *cdp, char *errbuf, size_t errlen)
+{
+ GElf_Ehdr ehdr;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "failed to get ELF header: %s\n",
+ elf_errmsg(elf_errno()));
+ return (ECTF_CONVBKERR);
+ }
+
+ cdp->cd_mach = ehdr.e_machine;
+
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ cdp->cd_ptrsz = 4;
+ VERIFY(ctf_setmodel(cdp->cd_ctfp, CTF_MODEL_ILP32) == 0);
+ } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ cdp->cd_ptrsz = 8;
+ VERIFY(ctf_setmodel(cdp->cd_ctfp, CTF_MODEL_LP64) == 0);
+ } else {
+ (void) snprintf(errbuf, errlen,
+ "unknown ELF class %d", ehdr.e_ident[EI_CLASS]);
+ return (ECTF_CONVBKERR);
+ }
+
+ if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
+ cdp->cd_bigend = B_FALSE;
+ } else if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) {
+ cdp->cd_bigend = B_TRUE;
+ } else {
+ (void) snprintf(errbuf, errlen,
+ "unknown ELF data encoding: %d", ehdr.e_ident[EI_DATA]);
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+typedef struct ctf_dwarf_fpent {
+ size_t cdfe_size;
+ uint_t cdfe_enc[3];
+} ctf_dwarf_fpent_t;
+
+typedef struct ctf_dwarf_fpmap {
+ uint_t cdf_mach;
+ ctf_dwarf_fpent_t cdf_ents[4];
+} ctf_dwarf_fpmap_t;
+
+static const ctf_dwarf_fpmap_t ctf_dwarf_fpmaps[] = {
+ { EM_SPARC, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_SPARC32PLUS, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_SPARCV9, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_386, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 12, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_X86_64, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_NONE }
+};
+
+static int
+ctf_dwarf_float_base(ctf_die_t *cdp, Dwarf_Signed type, ctf_encoding_t *enc)
+{
+ const ctf_dwarf_fpmap_t *map = &ctf_dwarf_fpmaps[0];
+ const ctf_dwarf_fpent_t *ent;
+ uint_t col = 0, mult = 1;
+
+ for (map = &ctf_dwarf_fpmaps[0]; map->cdf_mach != EM_NONE; map++) {
+ if (map->cdf_mach == cdp->cd_mach)
+ break;
+ }
+
+ if (map->cdf_mach == EM_NONE) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "Unsupported machine type: %d\n", cdp->cd_mach);
+ return (ENOTSUP);
+ }
+
+ if (type == DW_ATE_complex_float) {
+ mult = 2;
+ col = 1;
+ } else if (type == DW_ATE_imaginary_float ||
+ type == DW_ATE_SUN_imaginary_float) {
+ col = 2;
+ }
+
+ ent = &map->cdf_ents[0];
+ for (ent = &map->cdf_ents[0]; ent->cdfe_size != 0; ent++) {
+ if (ent->cdfe_size * mult * 8 == enc->cte_bits) {
+ enc->cte_format = ent->cdfe_enc[col];
+ return (0);
+ }
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to find valid fp mapping for encoding %d, size %d bits\n",
+ type, enc->cte_bits);
+ return (EINVAL);
+}
+
+static int
+ctf_dwarf_dwarf_base(ctf_die_t *cdp, Dwarf_Die die, int *kindp,
+ ctf_encoding_t *enc)
+{
+ int ret;
+ Dwarf_Signed type;
+
+ if ((ret = ctf_dwarf_signed(cdp, die, DW_AT_encoding, &type)) != 0)
+ return (ret);
+
+ switch (type) {
+ case DW_ATE_unsigned:
+ case DW_ATE_address:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = 0;
+ break;
+ case DW_ATE_unsigned_char:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_CHAR;
+ break;
+ case DW_ATE_signed:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED;
+ break;
+ case DW_ATE_signed_char:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED | CTF_INT_CHAR;
+ break;
+ case DW_ATE_boolean:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED | CTF_INT_BOOL;
+ break;
+ case DW_ATE_float:
+ case DW_ATE_complex_float:
+ case DW_ATE_imaginary_float:
+ case DW_ATE_SUN_imaginary_float:
+ case DW_ATE_SUN_interval_float:
+ *kindp = CTF_K_FLOAT;
+ if ((ret = ctf_dwarf_float_base(cdp, type, enc)) != 0)
+ return (ret);
+ break;
+ default:
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered unkown DWARF encoding: %d", type);
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+/*
+ * Different compilers (at least GCC and Studio) use different names for types.
+ * This parses the types and attempts to unify them. If this fails, we just fall
+ * back to using the DWARF itself.
+ */
+static int
+ctf_dwarf_parse_base(const char *name, int *kindp, ctf_encoding_t *enc,
+ char **newnamep)
+{
+ char buf[256];
+ char *base, *c;
+ int nlong = 0, nshort = 0, nchar = 0, nint = 0;
+ int sign = 1;
+
+ if (strlen(name) + 1 > sizeof (buf))
+ return (EINVAL);
+
+ (void) strlcpy(buf, name, sizeof (buf));
+ for (c = strtok(buf, " "); c != NULL; c = strtok(NULL, " ")) {
+ if (strcmp(c, "signed") == 0) {
+ sign = 1;
+ } else if (strcmp(c, "unsigned") == 0) {
+ sign = 0;
+ } else if (strcmp(c, "long") == 0) {
+ nlong++;
+ } else if (strcmp(c, "char") == 0) {
+ nchar++;
+ } else if (strcmp(c, "short") == 0) {
+ nshort++;
+ } else if (strcmp(c, "int") == 0) {
+ nint++;
+ } else {
+ /*
+ * If we don't recognize any of the tokens, we'll tell
+ * the caller to fall back to the dwarf-provided
+ * encoding information.
+ */
+ return (EINVAL);
+ }
+ }
+
+ if (nchar > 1 || nshort > 1 || nint > 1 || nlong > 2)
+ return (EINVAL);
+
+ if (nchar > 0) {
+ if (nlong > 0 || nshort > 0 || nint > 0)
+ return (EINVAL);
+ base = "char";
+ } else if (nshort > 0) {
+ if (nlong > 0)
+ return (EINVAL);
+ base = "short";
+ } else if (nlong > 0) {
+ base = "long";
+ } else {
+ base = "int";
+ }
+
+ if (nchar > 0)
+ enc->cte_format = CTF_INT_CHAR;
+ else
+ enc->cte_format = 0;
+
+ if (sign > 0)
+ enc->cte_format |= CTF_INT_SIGNED;
+
+ (void) snprintf(buf, sizeof (buf), "%s%s%s",
+ (sign ? "" : "unsigned "),
+ (nlong > 1 ? "long " : ""),
+ base);
+
+ *newnamep = ctf_strdup(buf);
+ if (*newnamep == NULL)
+ return (ENOMEM);
+ *kindp = CTF_K_INTEGER;
+ return (0);
+}
+
+static int
+ctf_dwarf_create_base(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot,
+ Dwarf_Off off)
+{
+ int ret;
+ char *name, *nname;
+ Dwarf_Unsigned sz;
+ int kind;
+ ctf_encoding_t enc;
+ ctf_id_t id;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size, &sz)) != 0) {
+ goto out;
+ }
+ ctf_dprintf("Creating base type %s from off %llu, size: %d\n", name,
+ off, sz);
+
+ bzero(&enc, sizeof (ctf_encoding_t));
+ enc.cte_bits = sz * 8;
+ if ((ret = ctf_dwarf_parse_base(name, &kind, &enc, &nname)) == 0) {
+ ctf_free(name, strlen(name) + 1);
+ name = nname;
+ } else {
+ if (ret != EINVAL)
+ return (ret);
+ ctf_dprintf("falling back to dwarf for base type %s\n", name);
+ if ((ret = ctf_dwarf_dwarf_base(cdp, die, &kind, &enc)) != 0)
+ return (ret);
+ }
+
+ id = ctf_add_encoded(cdp->cd_ctfp, isroot, name, &enc, kind);
+ if (id == CTF_ERR) {
+ ret = ctf_errno(cdp->cd_ctfp);
+ } else {
+ *idp = id;
+ ret = ctf_dwmap_add(cdp, id, die, B_FALSE);
+ }
+out:
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+}
+
+/*
+ * Getting a member's offset is a surprisingly intricate dance. It works as
+ * follows:
+ *
+ * 1) If we're in DWARFv4, then we either have a DW_AT_data_bit_offset or we
+ * have a DW_AT_data_member_location. We won't have both. Thus we check first
+ * for DW_AT_data_bit_offset, and if it exists, we're set.
+ *
+ * Next, if we have a bitfield and we don't ahve a DW_AT_data_bit_offset, then
+ * we have to grab the data location and use the following dance:
+ *
+ * 2) Gather the set of DW_AT_byte_size, DW_AT_bit_offset, and DW_AT_bit_size.
+ * Of course, the DW_AT_byte_size may be omitted, even though it isn't always.
+ * When it's been omitted, we then have to say that the size is that of the
+ * underlying type, which forces that to be after a ctf_update(). Here, we have
+ * to do different things based on whether or not we're using big endian or
+ * little endian to obtain the proper offset.
+ */
+static int
+ctf_dwarf_member_offset(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t mid,
+ ulong_t *offp)
+{
+ int ret;
+ Dwarf_Unsigned loc, bitsz, bytesz;
+ Dwarf_Signed bitoff;
+ size_t off, tsz;
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_data_bit_offset,
+ &loc)) == 0) {
+ *offp = loc;
+ return (0);
+ } else if (ret != ENOENT) {
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_member_location(cdp, die, &loc)) != 0)
+ return (ret);
+ off = loc * 8;
+
+ if ((ret = ctf_dwarf_signed(cdp, die, DW_AT_bit_offset,
+ &bitoff)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ *offp = off;
+ return (0);
+ }
+
+ /* At this point we have to have DW_AT_bit_size */
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_bit_size, &bitsz)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size,
+ &bytesz)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ if ((tsz = ctf_type_size(cdp->cd_ctfp, mid)) == CTF_ERR) {
+ int e = ctf_errno(cdp->cd_ctfp);
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get type size: %s", ctf_errmsg(e));
+ return (ECTF_CONVBKERR);
+ }
+ } else {
+ tsz = bytesz;
+ }
+ tsz *= 8;
+ if (cdp->cd_bigend == B_TRUE) {
+ *offp = off + bitoff;
+ } else {
+ *offp = off + tsz - bitoff - bitsz;
+ }
+
+ return (0);
+}
+
+/*
+ * We need to determine if the member in question is a bitfield. If it is, then
+ * we need to go through and create a new type that's based on the actual base
+ * type, but has a different size. We also rename the type as a result to help
+ * deal with future collisions.
+ *
+ * Here we need to look and see if we have a DW_AT_bit_size value. If we have a
+ * bit size member and it does not equal the byte size member, then we need to
+ * create a bitfield type based on this.
+ *
+ * Note: When we support DWARFv4, there may be a chance that we ned to also
+ * search for the DW_AT_byte_size if we don't have a DW_AT_bit_size member.
+ */
+static int
+ctf_dwarf_member_bitfield(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp)
+{
+ int ret;
+ Dwarf_Unsigned bitsz;
+ ctf_encoding_t e;
+ ctf_dwbitf_t *cdb;
+ ctf_dtdef_t *dtd;
+ ctf_id_t base = *idp;
+ int kind;
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_bit_size, &bitsz)) != 0) {
+ if (ret == ENOENT)
+ return (0);
+ return (ret);
+ }
+
+ ctf_dprintf("Trying to deal with bitfields on %d:%d\n", base, bitsz);
+ /*
+ * Given that we now have a bitsize, time to go do something about it.
+ * We're going to create a new type based on the current one, but first
+ * we need to find the base type. This means we need to traverse any
+ * typedef's, consts, and volatiles until we get to what should be
+ * something of type integer or enumeration.
+ */
+ VERIFY(bitsz < UINT32_MAX);
+ dtd = ctf_dtd_lookup(cdp->cd_ctfp, base);
+ VERIFY(dtd != NULL);
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ while (kind == CTF_K_TYPEDEF || kind == CTF_K_CONST ||
+ kind == CTF_K_VOLATILE) {
+ dtd = ctf_dtd_lookup(cdp->cd_ctfp, dtd->dtd_data.ctt_type);
+ VERIFY(dtd != NULL);
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ }
+ ctf_dprintf("got kind %d\n", kind);
+ VERIFY(kind == CTF_K_INTEGER || kind == CTF_K_ENUM);
+
+ /*
+ * As surprising as it may be, it is strictly possible to create a
+ * bitfield that is based on an enum. Of course, the C standard leaves
+ * enums sizing as an ABI concern more or less. To that effect, today on
+ * all illumos platforms the size of an enum is generally that of an
+ * int as our supported data models and ABIs all agree on that. So what
+ * we'll do is fake up a CTF enconding here to use. In this case, we'll
+ * treat it as an unsigned value of whatever size the underlying enum
+ * currently has (which is in the ctt_size member of its dynamic type
+ * data).
+ */
+ if (kind == CTF_K_INTEGER) {
+ e = dtd->dtd_u.dtu_enc;
+ } else {
+ bzero(&e, sizeof (ctf_encoding_t));
+ e.cte_bits = dtd->dtd_data.ctt_size * NBBY;
+ }
+
+ for (cdb = ctf_list_next(&cdp->cd_bitfields); cdb != NULL;
+ cdb = ctf_list_next(cdb)) {
+ if (cdb->cdb_base == base && cdb->cdb_nbits == bitsz)
+ break;
+ }
+
+ /*
+ * Create a new type if none exists. We name all types in a way that is
+ * guaranteed not to conflict with the corresponding C type. We do this
+ * by using the ':' operator.
+ */
+ if (cdb == NULL) {
+ size_t namesz;
+ char *name;
+
+ e.cte_bits = bitsz;
+ namesz = snprintf(NULL, 0, "%s:%d", dtd->dtd_name,
+ (uint32_t)bitsz);
+ name = ctf_alloc(namesz + 1);
+ if (name == NULL)
+ return (ENOMEM);
+ cdb = ctf_alloc(sizeof (ctf_dwbitf_t));
+ if (cdb == NULL) {
+ ctf_free(name, namesz + 1);
+ return (ENOMEM);
+ }
+ (void) snprintf(name, namesz + 1, "%s:%d", dtd->dtd_name,
+ (uint32_t)bitsz);
+
+ cdb->cdb_base = base;
+ cdb->cdb_nbits = bitsz;
+ cdb->cdb_id = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_NONROOT,
+ name, &e);
+ if (cdb->cdb_id == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get add bitfield type %s: %s", name,
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ ctf_free(name, namesz + 1);
+ ctf_free(cdb, sizeof (ctf_dwbitf_t));
+ return (ECTF_CONVBKERR);
+ }
+ ctf_free(name, namesz + 1);
+ ctf_list_append(&cdp->cd_bitfields, cdb);
+ }
+
+ *idp = cdb->cdb_id;
+
+ return (0);
+}
+
+static int
+ctf_dwarf_fixup_sou(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t base, boolean_t add)
+{
+ int ret, kind;
+ Dwarf_Die child, memb;
+ Dwarf_Unsigned size;
+ ulong_t nsz;
+
+ kind = ctf_type_kind(cdp->cd_ctfp, base);
+ VERIFY(kind != CTF_ERR);
+ VERIFY(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
+
+ /*
+ * Members are in children. However, gcc also allows empty ones.
+ */
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+ if (child == NULL)
+ return (0);
+
+ memb = child;
+ while (memb != NULL) {
+ Dwarf_Die sib, tdie;
+ Dwarf_Half tag;
+ ctf_id_t mid;
+ char *mname;
+ ulong_t memboff = 0;
+
+ if ((ret = ctf_dwarf_tag(cdp, memb, &tag)) != 0)
+ return (ret);
+
+ if (tag != DW_TAG_member)
+ continue;
+
+ if ((ret = ctf_dwarf_refdie(cdp, memb, DW_AT_type, &tdie)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &mid,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ ctf_dprintf("Got back type id: %d\n", mid);
+
+ /*
+ * If we're not adding a member, just go ahead and return.
+ */
+ if (add == B_FALSE) {
+ if ((ret = ctf_dwarf_member_bitfield(cdp, memb,
+ &mid)) != 0)
+ return (ret);
+ goto next;
+ }
+
+ if ((ret = ctf_dwarf_string(cdp, memb, DW_AT_name,
+ &mname)) != 0 && ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ mname = NULL;
+
+ if (kind == CTF_K_UNION) {
+ memboff = 0;
+ } else if ((ret = ctf_dwarf_member_offset(cdp, memb, mid,
+ &memboff)) != 0) {
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_member_bitfield(cdp, memb, &mid)) != 0)
+ return (ret);
+
+ ret = ctf_add_member(cdp->cd_ctfp, base, mname, mid, memboff);
+ if (ret == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to add member %s: %s",
+ mname, ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+ return (ECTF_CONVBKERR);
+ }
+
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+
+next:
+ if ((ret = ctf_dwarf_sib(cdp, memb, &sib)) != 0)
+ return (ret);
+ memb = sib;
+ }
+
+ /*
+ * If we're not adding members, then we don't know the final size of the
+ * structure, so end here.
+ */
+ if (add == B_FALSE)
+ return (0);
+
+ /* Finally set the size of the structure to the actual byte size */
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size, &size)) != 0)
+ return (ret);
+ nsz = size;
+ if ((ctf_set_size(cdp->cd_ctfp, base, nsz)) == CTF_ERR) {
+ int e = ctf_errno(cdp->cd_ctfp);
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to set type size for %d to 0x%x: %s", base,
+ (uint32_t)size, ctf_errmsg(e));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_create_sou(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int kind, int isroot)
+{
+ int ret;
+ char *name;
+ ctf_id_t base;
+ Dwarf_Die child;
+ Dwarf_Bool decl;
+
+ /*
+ * Deal with the terribly annoying case of anonymous structs and unions.
+ * If they don't have a name, set the name to the empty string.
+ */
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ name = NULL;
+
+ /*
+ * We need to check if we just have a declaration here. If we do, then
+ * instead of creating an actual structure or union, we're just going to
+ * go ahead and create a forward. During a dedup or merge, the forward
+ * will be replaced with the real thing.
+ */
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration,
+ &decl)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ decl = 0;
+ }
+
+ if (decl != 0) {
+ base = ctf_add_forward(cdp->cd_ctfp, isroot, name, kind);
+ } else if (kind == CTF_K_STRUCT) {
+ base = ctf_add_struct(cdp->cd_ctfp, isroot, name);
+ } else {
+ base = ctf_add_union(cdp->cd_ctfp, isroot, name);
+ }
+ ctf_dprintf("added sou %s (%d) (%d)\n", name, kind, base);
+ if (name != NULL)
+ ctf_free(name, strlen(name) + 1);
+ if (base == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ *idp = base;
+
+ /*
+ * If it's just a declaration, we're not going to mark it for fix up or
+ * do anything else.
+ */
+ if (decl == B_TRUE)
+ return (ctf_dwmap_add(cdp, base, die, B_FALSE));
+ if ((ret = ctf_dwmap_add(cdp, base, die, B_TRUE)) != 0)
+ return (ret);
+
+ /*
+ * Members are in children. However, gcc also allows empty ones.
+ */
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+ if (child == NULL)
+ return (0);
+
+ return (0);
+}
+
+static int
+ctf_dwarf_create_array_range(ctf_die_t *cdp, Dwarf_Die range, ctf_id_t *idp,
+ ctf_id_t base, int isroot)
+{
+ int ret;
+ Dwarf_Die sib;
+ Dwarf_Unsigned val;
+ Dwarf_Signed sval;
+ ctf_arinfo_t ar;
+
+ ctf_dprintf("creating array range\n");
+
+ if ((ret = ctf_dwarf_sib(cdp, range, &sib)) != 0)
+ return (ret);
+ if (sib != NULL) {
+ ctf_id_t id;
+ if ((ret = ctf_dwarf_create_array_range(cdp, sib, &id,
+ base, CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ ar.ctr_contents = id;
+ } else {
+ ar.ctr_contents = base;
+ }
+
+ if ((ar.ctr_index = ctf_dwarf_long(cdp)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ /*
+ * Array bounds can be signed or unsigned, but there are several kinds
+ * of signless forms (data1, data2, etc) that take their sign from the
+ * routine that is trying to interpret them. That is, data1 can be
+ * either signed or unsigned, depending on whether you use the signed or
+ * unsigned accessor function. GCC will use the signless forms to store
+ * unsigned values which have their high bit set, so we need to try to
+ * read them first as unsigned to get positive values. We could also
+ * try signed first, falling back to unsigned if we got a negative
+ * value.
+ */
+ if ((ret = ctf_dwarf_unsigned(cdp, range, DW_AT_upper_bound,
+ &val)) == 0) {
+ ar.ctr_nelems = val + 1;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else if ((ret = ctf_dwarf_signed(cdp, range, DW_AT_upper_bound,
+ &sval)) == 0) {
+ ar.ctr_nelems = sval + 1;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else {
+ ar.ctr_nelems = 0;
+ }
+
+ if ((*idp = ctf_add_array(cdp->cd_ctfp, isroot, &ar)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+/*
+ * Try and create an array type. First, the kind of the array is specified in
+ * the DW_AT_type entry. Next, the number of entries is stored in a more
+ * complicated form, we should have a child that has the DW_TAG_subrange type.
+ */
+static int
+ctf_dwarf_create_array(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ Dwarf_Die tdie, rdie;
+ ctf_id_t tid;
+ Dwarf_Half rtag;
+ ctf_arinfo_t ar;
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &tid,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+
+ ar.ctr_contents = tid;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &rdie)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_tag(cdp, rdie, &rtag)) != 0)
+ return (ret);
+ if (rtag != DW_TAG_subrange_type) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered array without DW_TAG_subrange_type child\n");
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * The compiler may opt to describe a multi-dimensional array as one
+ * giant array or it may opt to instead encode it as a series of
+ * subranges. If it's the latter, then for each subrange we introduce a
+ * type. We can always use the base type.
+ */
+ if ((ret = ctf_dwarf_create_array_range(cdp, rdie, idp, tid,
+ isroot)) != 0)
+ return (ret);
+ ctf_dprintf("Got back id %d\n", *idp);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_create_reference(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int kind, int isroot)
+{
+ int ret;
+ ctf_id_t id;
+ Dwarf_Die tdie;
+ char *name;
+ size_t namelen;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT) {
+ name = NULL;
+ namelen = 0;
+ } else {
+ namelen = strlen(name);
+ }
+
+ ctf_dprintf("reference kind %d %s\n", kind, name != NULL ? name : "<>");
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0) {
+ if (ret != ENOENT) {
+ ctf_free(name, namelen);
+ return (ret);
+ }
+ if ((id = ctf_dwarf_void(cdp)) == CTF_ERR) {
+ ctf_free(name, namelen);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ } else {
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &id,
+ CTF_ADD_NONROOT)) != 0) {
+ ctf_free(name, namelen);
+ return (ret);
+ }
+ }
+
+ if ((*idp = ctf_add_reftype(cdp->cd_ctfp, isroot, name, id, kind)) ==
+ CTF_ERR) {
+ ctf_free(name, namelen);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ ctf_free(name, namelen);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_create_enum(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ ctf_id_t id;
+ Dwarf_Die child;
+ char *name;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ name = NULL;
+ id = ctf_add_enum(cdp->cd_ctfp, isroot, name);
+ ctf_dprintf("added enum %s (%d)\n", name, id);
+ if (name != NULL)
+ ctf_free(name, strlen(name) + 1);
+ if (id == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ *idp = id;
+ if ((ret = ctf_dwmap_add(cdp, id, die, B_FALSE)) != 0)
+ return (ret);
+
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0) {
+ if (ret == ENOENT)
+ ret = 0;
+ return (ret);
+ }
+
+ while (child != NULL) {
+ Dwarf_Half tag;
+ Dwarf_Signed sval;
+ Dwarf_Unsigned uval;
+ Dwarf_Die arg = child;
+ int eval;
+
+ if ((ret = ctf_dwarf_sib(cdp, arg, &child)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+
+ if (tag != DW_TAG_enumerator) {
+ if ((ret = ctf_dwarf_convert_type(cdp, arg, NULL,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ continue;
+ }
+
+ if ((ret = ctf_dwarf_signed(cdp, arg, DW_AT_const_value,
+ &sval)) == 0) {
+ eval = sval;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else if ((ret = ctf_dwarf_unsigned(cdp, arg,
+ DW_AT_const_value, &uval)) == 0) {
+ eval = (int)uval;
+ } else {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered enumration without constant value\n");
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * DWARF v4 section 5.7 tells us we'll always have names.
+ */
+ if ((ret = ctf_dwarf_string(cdp, arg, DW_AT_name,
+ &name)) != 0)
+ return (ret);
+
+ ret = ctf_add_enumerator(cdp->cd_ctfp, id, name, eval);
+ if (ret == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to add enumarator %s (%d) to %d\n",
+ name, eval, id);
+ ctf_free(name, strlen(name) + 1);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ ctf_free(name, strlen(name) + 1);
+ }
+
+ return (0);
+}
+
+/*
+ * For a function pointer, walk over and process all of its children, unless we
+ * encounter one that's just a declaration. In which case, we error on it.
+ */
+static int
+ctf_dwarf_create_fptr(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ Dwarf_Bool b;
+ ctf_funcinfo_t fi;
+ Dwarf_Die retdie;
+ ctf_id_t *argv = NULL;
+
+ bzero(&fi, sizeof (ctf_funcinfo_t));
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ } else {
+ if (b != 0)
+ return (EPROTOTYPE);
+ }
+
+ /*
+ * Return type is in DW_AT_type, if none, it returns void.
+ */
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &retdie)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ if ((fi.ctc_return = ctf_dwarf_void(cdp)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ } else {
+ if ((ret = ctf_dwarf_convert_type(cdp, retdie, &fi.ctc_return,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_function_count(cdp, die, &fi, B_TRUE)) != 0) {
+ return (ret);
+ }
+
+ if (fi.ctc_argc != 0) {
+ argv = ctf_alloc(sizeof (ctf_id_t) * fi.ctc_argc);
+ if (argv == NULL)
+ return (ENOMEM);
+
+ if ((ret = ctf_dwarf_convert_fargs(cdp, die, &fi, argv)) != 0) {
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ret);
+ }
+ }
+
+ if ((*idp = ctf_add_funcptr(cdp->cd_ctfp, isroot, &fi, argv)) ==
+ CTF_ERR) {
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_convert_type(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int isroot)
+{
+ int ret;
+ Dwarf_Off offset;
+ Dwarf_Half tag;
+ ctf_dwmap_t lookup, *map;
+ ctf_id_t id;
+
+ if (idp == NULL)
+ idp = &id;
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &offset)) != 0)
+ return (ret);
+
+ if (offset > cdp->cd_maxoff) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "die offset %llu beyond maximum for header %llu\n",
+ offset, cdp->cd_maxoff);
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * If we've already added an entry for this offset, then we're done.
+ */
+ lookup.cdm_off = offset;
+ if ((map = avl_find(&cdp->cd_map, &lookup, NULL)) != NULL) {
+ *idp = map->cdm_id;
+ return (0);
+ }
+
+ if ((ret = ctf_dwarf_tag(cdp, die, &tag)) != 0)
+ return (ret);
+
+ ret = ENOTSUP;
+ switch (tag) {
+ case DW_TAG_base_type:
+ ctf_dprintf("base\n");
+ ret = ctf_dwarf_create_base(cdp, die, idp, isroot, offset);
+ break;
+ case DW_TAG_array_type:
+ ctf_dprintf("array\n");
+ ret = ctf_dwarf_create_array(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_enumeration_type:
+ ctf_dprintf("enum\n");
+ ret = ctf_dwarf_create_enum(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_pointer_type:
+ ctf_dprintf("pointer\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_POINTER,
+ isroot);
+ break;
+ case DW_TAG_structure_type:
+ ctf_dprintf("struct\n");
+ ret = ctf_dwarf_create_sou(cdp, die, idp, CTF_K_STRUCT,
+ isroot);
+ break;
+ case DW_TAG_subroutine_type:
+ ctf_dprintf("fptr\n");
+ ret = ctf_dwarf_create_fptr(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_typedef:
+ ctf_dprintf("typedef\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_TYPEDEF,
+ isroot);
+ break;
+ case DW_TAG_union_type:
+ ctf_dprintf("union\n");
+ ret = ctf_dwarf_create_sou(cdp, die, idp, CTF_K_UNION,
+ isroot);
+ break;
+ case DW_TAG_const_type:
+ ctf_dprintf("const\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_CONST,
+ isroot);
+ break;
+ case DW_TAG_volatile_type:
+ ctf_dprintf("volatile\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_VOLATILE,
+ isroot);
+ break;
+ case DW_TAG_restrict_type:
+ ctf_dprintf("restrict\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_RESTRICT,
+ isroot);
+ break;
+ default:
+ ctf_dprintf("ignoring tag type %x\n", tag);
+ ret = 0;
+ break;
+ }
+ ctf_dprintf("ctf_dwarf_convert_type tag specific handler returned %d\n",
+ ret);
+
+ return (ret);
+}
+
+static int
+ctf_dwarf_walk_lexical(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ Dwarf_Die child;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ if (child == NULL)
+ return (0);
+
+ return (ctf_dwarf_convert_die(cdp, die));
+}
+
+static int
+ctf_dwarf_function_count(ctf_die_t *cdp, Dwarf_Die die, ctf_funcinfo_t *fip,
+ boolean_t fptr)
+{
+ int ret;
+ Dwarf_Die child, sib, arg;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ arg = child;
+ while (arg != NULL) {
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+
+ /*
+ * We have to check for a varargs type decleration. This will
+ * happen in one of two ways. If we have a function pointer
+ * type, then it'll be done with a tag of type
+ * DW_TAG_unspecified_parameters. However, it only means we have
+ * a variable number of arguments, if we have more than one
+ * argument found so far. Otherwise, when we have a function
+ * type, it instead uses a formal parameter whose name is '...'
+ * to indicate a variable arguments member.
+ *
+ * Also, if we have a function pointer, then we have to expect
+ * that we might not get a name at all.
+ */
+ if (tag == DW_TAG_formal_parameter && fptr == B_FALSE) {
+ char *name;
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name,
+ &name)) != 0)
+ return (ret);
+ if (strcmp(name, DWARF_VARARGS_NAME) == 0)
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ else
+ fip->ctc_argc++;
+ ctf_free(name, strlen(name) + 1);
+ } else if (tag == DW_TAG_formal_parameter) {
+ fip->ctc_argc++;
+ } else if (tag == DW_TAG_unspecified_parameters &&
+ fip->ctc_argc > 0) {
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ }
+ if ((ret = ctf_dwarf_sib(cdp, arg, &sib)) != 0)
+ return (ret);
+ arg = sib;
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_convert_fargs(ctf_die_t *cdp, Dwarf_Die die, ctf_funcinfo_t *fip,
+ ctf_id_t *argv)
+{
+ int ret;
+ int i = 0;
+ Dwarf_Die child, sib, arg;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ arg = child;
+ while (arg != NULL) {
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+ if (tag == DW_TAG_formal_parameter) {
+ Dwarf_Die tdie;
+
+ if ((ret = ctf_dwarf_refdie(cdp, arg, DW_AT_type,
+ &tdie)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &argv[i],
+ CTF_ADD_ROOT)) != 0)
+ return (ret);
+ i++;
+
+ /*
+ * Once we hit argc entries, we're done. This ensures we
+ * don't accidentally hit a varargs which should be the
+ * least entry.
+ */
+ if (i == fip->ctc_argc)
+ break;
+ }
+
+ if ((ret = ctf_dwarf_sib(cdp, arg, &sib)) != 0)
+ return (ret);
+ arg = sib;
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_convert_function(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ char *name;
+ ctf_dwfunc_t *cdf;
+ Dwarf_Die tdie;
+
+ /*
+ * Functions that don't have a name are generally functions that have
+ * been inlined and thus most information about them has been lost. If
+ * we can't get a name, then instead of returning ENOENT, we silently
+ * swallow the error.
+ */
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0) {
+ if (ret == ENOENT)
+ return (0);
+ return (ret);
+ }
+
+ ctf_dprintf("beginning work on function %s\n", name);
+ if ((cdf = ctf_alloc(sizeof (ctf_dwfunc_t))) == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ return (ENOMEM);
+ }
+ bzero(cdf, sizeof (ctf_dwfunc_t));
+ cdf->cdf_name = name;
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) == 0) {
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie,
+ &(cdf->cdf_fip.ctc_return), CTF_ADD_ROOT)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+ } else if (ret != ENOENT) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ } else {
+ if ((cdf->cdf_fip.ctc_return = ctf_dwarf_void(cdp)) ==
+ CTF_ERR) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ }
+
+ /*
+ * A function has a number of children, some of which may not be ones we
+ * care about. Children that we care about have a type of
+ * DW_TAG_formal_parameter. We're going to do two passes, the first to
+ * count the arguments, the second to process them. Afterwards, we
+ * should be good to go ahead and add this function.
+ *
+ * Note, we already got the return type by going in and grabbing it out
+ * of the DW_AT_type.
+ */
+ if ((ret = ctf_dwarf_function_count(cdp, die, &cdf->cdf_fip,
+ B_FALSE)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+
+ ctf_dprintf("beginning to convert function arguments %s\n", name);
+ if (cdf->cdf_fip.ctc_argc != 0) {
+ uint_t argc = cdf->cdf_fip.ctc_argc;
+ cdf->cdf_argv = ctf_alloc(sizeof (ctf_id_t) * argc);
+ if (cdf->cdf_argv == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ENOMEM);
+ }
+ if ((ret = ctf_dwarf_convert_fargs(cdp, die,
+ &cdf->cdf_fip, cdf->cdf_argv)) != 0) {
+ ctf_free(cdf->cdf_argv, sizeof (ctf_id_t) * argc);
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+ } else {
+ cdf->cdf_argv = NULL;
+ }
+
+ if ((ret = ctf_dwarf_isglobal(cdp, die, &cdf->cdf_global)) != 0) {
+ ctf_free(cdf->cdf_argv, sizeof (ctf_id_t) *
+ cdf->cdf_fip.ctc_argc);
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+
+ ctf_list_append(&cdp->cd_funcs, cdf);
+ return (ret);
+}
+
+/*
+ * Convert variables, but only if they're not prototypes and have names.
+ */
+static int
+ctf_dwarf_convert_variable(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ char *name;
+ Dwarf_Bool b;
+ Dwarf_Die tdie;
+ ctf_id_t id;
+ ctf_dwvar_t *cdv;
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ } else if (b != 0) {
+ return (0);
+ }
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ return (0);
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &id,
+ CTF_ADD_ROOT)) != 0)
+ return (ret);
+
+ if ((cdv = ctf_alloc(sizeof (ctf_dwvar_t))) == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ return (ENOMEM);
+ }
+
+ cdv->cdv_name = name;
+ cdv->cdv_type = id;
+
+ if ((ret = ctf_dwarf_isglobal(cdp, die, &cdv->cdv_global)) != 0) {
+ ctf_free(cdv, sizeof (ctf_dwvar_t));
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+ }
+
+ ctf_list_append(&cdp->cd_vars, cdv);
+ return (0);
+}
+
+/*
+ * Walk through our set of top-level types and process them.
+ */
+static int
+ctf_dwarf_walk_toplevel(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ Dwarf_Off offset;
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &offset)) != 0)
+ return (ret);
+
+ if (offset > cdp->cd_maxoff) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "die offset %llu beyond maximum for header %llu\n",
+ offset, cdp->cd_maxoff);
+ return (ECTF_CONVBKERR);
+ }
+
+ if ((ret = ctf_dwarf_tag(cdp, die, &tag)) != 0)
+ return (ret);
+
+ ret = 0;
+ switch (tag) {
+ case DW_TAG_subprogram:
+ ctf_dprintf("top level func\n");
+ ret = ctf_dwarf_convert_function(cdp, die);
+ break;
+ case DW_TAG_variable:
+ ctf_dprintf("top level var\n");
+ ret = ctf_dwarf_convert_variable(cdp, die);
+ break;
+ case DW_TAG_lexical_block:
+ ctf_dprintf("top level block\n");
+ ret = ctf_dwarf_walk_lexical(cdp, die);
+ break;
+ case DW_TAG_enumeration_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ ctf_dprintf("top level type\n");
+ ret = ctf_dwarf_convert_type(cdp, die, NULL, B_TRUE);
+ break;
+ default:
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * We're given a node. At this node we need to convert it and then proceed to
+ * convert any siblings that are associaed with this die.
+ */
+static int
+ctf_dwarf_convert_die(ctf_die_t *cdp, Dwarf_Die die)
+{
+ while (die != NULL) {
+ int ret;
+ Dwarf_Die sib;
+
+ if ((ret = ctf_dwarf_walk_toplevel(cdp, die)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_sib(cdp, die, &sib)) != 0)
+ return (ret);
+ die = sib;
+ }
+ return (0);
+}
+
+static int
+ctf_dwarf_fixup_die(ctf_die_t *cdp, boolean_t addpass)
+{
+ ctf_dwmap_t *map;
+
+ for (map = avl_first(&cdp->cd_map); map != NULL;
+ map = AVL_NEXT(&cdp->cd_map, map)) {
+ int ret;
+ if (map->cdm_fix == B_FALSE)
+ continue;
+ if ((ret = ctf_dwarf_fixup_sou(cdp, map->cdm_die, map->cdm_id,
+ addpass)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static ctf_dwfunc_t *
+ctf_dwarf_match_func(ctf_die_t *cdp, const char *file, const char *name,
+ int bind)
+{
+ ctf_dwfunc_t *cdf;
+
+ if (bind == STB_WEAK)
+ return (NULL);
+
+ /* Nothing we can do if we can't find a name to compare it to. */
+ if (bind == STB_LOCAL && (file == NULL || cdp->cd_name == NULL))
+ return (NULL);
+
+ for (cdf = ctf_list_next(&cdp->cd_funcs); cdf != NULL;
+ cdf = ctf_list_next(cdf)) {
+ if (bind == STB_GLOBAL && cdf->cdf_global == B_FALSE)
+ continue;
+ if (bind == STB_LOCAL && cdf->cdf_global == B_TRUE)
+ continue;
+ if (strcmp(name, cdf->cdf_name) != 0)
+ continue;
+ if (bind == STB_LOCAL && strcmp(file, cdp->cd_name) != 0)
+ continue;
+ return (cdf);
+ }
+
+ return (NULL);
+}
+static ctf_dwvar_t *
+ctf_dwarf_match_var(ctf_die_t *cdp, const char *file, const char *name,
+ int bind)
+{
+ ctf_dwvar_t *cdv;
+
+ /* Nothing we can do if we can't find a name to compare it to. */
+ if (bind == STB_LOCAL && (file == NULL || cdp->cd_name == NULL))
+ return (NULL);
+ ctf_dprintf("Still considering %s\n", name);
+
+ for (cdv = ctf_list_next(&cdp->cd_vars); cdv != NULL;
+ cdv = ctf_list_next(cdv)) {
+ if (bind == STB_GLOBAL && cdv->cdv_global == B_FALSE)
+ continue;
+ if (bind == STB_LOCAL && cdv->cdv_global == B_TRUE)
+ continue;
+ if (strcmp(name, cdv->cdv_name) != 0)
+ continue;
+ if (bind == STB_LOCAL && strcmp(file, cdp->cd_name) != 0)
+ continue;
+ return (cdv);
+ }
+
+ return (NULL);
+}
+
+static int
+ctf_dwarf_symtab_iter(ctf_die_t *cdp, ctf_dwarf_symtab_f *func, void *arg)
+{
+ int ret;
+ ulong_t i;
+ ctf_file_t *fp = cdp->cd_ctfp;
+ const char *file = NULL;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ int type;
+ GElf_Sym gsym;
+ const GElf_Sym *gsymp;
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ type = ELF32_ST_TYPE(symp->st_info);
+ if (type == STT_FILE) {
+ file = (char *)(strbase + symp->st_name);
+ continue;
+ }
+ if (type != STT_OBJECT && type != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ gsym.st_name = symp->st_name;
+ gsym.st_value = symp->st_value;
+ gsym.st_size = symp->st_size;
+ gsym.st_info = symp->st_info;
+ gsym.st_other = symp->st_other;
+ gsym.st_shndx = symp->st_shndx;
+ gsymp = &gsym;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ type = ELF64_ST_TYPE(symp->st_info);
+ if (type == STT_FILE) {
+ file = (char *)(strbase + symp->st_name);
+ continue;
+ }
+ if (type != STT_OBJECT && type != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ gsymp = symp;
+ }
+
+ ret = func(cdp, gsymp, i, file, name, arg);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_funcvars_cb(ctf_die_t *cdp, const GElf_Sym *symp, ulong_t idx,
+ const char *file, const char *name, void *arg)
+{
+ int ret, bind, type;
+
+ bind = GELF_ST_BIND(symp->st_info);
+ type = GELF_ST_TYPE(symp->st_info);
+
+ /*
+ * Come back to weak symbols in another pass
+ */
+ if (bind == STB_WEAK)
+ return (0);
+
+ if (type == STT_OBJECT) {
+ ctf_dwvar_t *cdv = ctf_dwarf_match_var(cdp, file, name,
+ bind);
+ ctf_dprintf("match for %s (%d): %p\n", name, idx, cdv);
+ if (cdv == NULL)
+ return (0);
+ ret = ctf_add_object(cdp->cd_ctfp, idx, cdv->cdv_type);
+ ctf_dprintf("added object %s\n", name);
+ } else {
+ ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cdp, file, name,
+ bind);
+ if (cdf == NULL)
+ return (0);
+ ret = ctf_add_function(cdp->cd_ctfp, idx, &cdf->cdf_fip,
+ cdf->cdf_argv);
+ }
+
+ if (ret == CTF_ERR) {
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_funcvars(ctf_die_t *cdp)
+{
+ return (ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_funcvars_cb, NULL));
+}
+
+/*
+ * Note, this comment comes from the original version of the CTF tools.
+ *
+ * If we have a weak symbol, attempt to find the strong symbol it will
+ * resolve to. Note: the code where this actually happens is in
+ * sym_process() in cmd/sgs/libld/common/syms.c
+ *
+ * Finding the matching symbol is unfortunately not trivial. For a
+ * symbol to be a candidate, it must:
+ *
+ * - have the same type (function, object)
+ * - have the same value (address)
+ * - have the same size
+ * - not be another weak symbol
+ * - belong to the same section (checked via section index)
+ *
+ * If such a candidate is global, then we assume we've found it. The
+ * linker generates the symbol table such that the curfile might be
+ * incorrect; this is OK for global symbols, since find_iidesc() doesn't
+ * need to check for the source file for the symbol.
+ *
+ * We might have found a strong local symbol, where the curfile is
+ * accurate and matches that of the weak symbol. We assume this is a
+ * reasonable match.
+ *
+ * If we've got a local symbol with a non-matching curfile, there are
+ * two possibilities. Either this is a completely different symbol, or
+ * it's a once-global symbol that was scoped to local via a mapfile. In
+ * the latter case, curfile is likely inaccurate since the linker does
+ * not preserve the needed curfile in the order of the symbol table (see
+ * the comments about locally scoped symbols in libld's update_osym()).
+ * As we can't tell this case from the former one, we use this symbol
+ * iff no other matching symbol is found.
+ *
+ * What we really need here is a SUNW section containing weak<->strong
+ * mappings that we can consume.
+ */
+typedef struct ctf_dwarf_weak_arg {
+ const GElf_Sym *cweak_symp;
+ const char *cweak_file;
+ boolean_t cweak_candidate;
+ ulong_t cweak_idx;
+} ctf_dwarf_weak_arg_t;
+
+static int
+ctf_dwarf_conv_check_weak(ctf_die_t *cdp, const GElf_Sym *symp,
+ ulong_t idx, const char *file, const char *name, void *arg)
+{
+ ctf_dwarf_weak_arg_t *cweak = arg;
+ const GElf_Sym *wsymp = cweak->cweak_symp;
+
+ ctf_dprintf("comparing weak to %s\n", name);
+
+ if (GELF_ST_BIND(symp->st_info) == STB_WEAK) {
+ return (0);
+ }
+
+ if (GELF_ST_TYPE(wsymp->st_info) != GELF_ST_TYPE(symp->st_info)) {
+ return (0);
+ }
+
+ if (wsymp->st_value != symp->st_value) {
+ return (0);
+ }
+
+ if (wsymp->st_size != symp->st_size) {
+ return (0);
+ }
+
+ if (wsymp->st_shndx != symp->st_shndx) {
+ return (0);
+ }
+
+ /*
+ * Check if it's a weak candidate.
+ */
+ if (GELF_ST_BIND(symp->st_info) == STB_LOCAL &&
+ (file == NULL || cweak->cweak_file == NULL ||
+ strcmp(file, cweak->cweak_file) != 0)) {
+ cweak->cweak_candidate = B_TRUE;
+ cweak->cweak_idx = idx;
+ return (0);
+ }
+
+ /*
+ * Found a match, break.
+ */
+ cweak->cweak_idx = idx;
+ return (1);
+}
+
+static int
+ctf_dwarf_duplicate_sym(ctf_die_t *cdp, ulong_t idx, ulong_t matchidx)
+{
+ ctf_id_t id = ctf_lookup_by_symbol(cdp->cd_ctfp, matchidx);
+
+ /*
+ * If we matched something that for some reason didn't have type data,
+ * we don't consider that a fatal error and silently swallow it.
+ */
+ if (id == CTF_ERR) {
+ if (ctf_errno(cdp->cd_ctfp) == ECTF_NOTYPEDAT)
+ return (0);
+ else
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ if (ctf_add_object(cdp->cd_ctfp, idx, id) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+static int
+ctf_dwarf_duplicate_func(ctf_die_t *cdp, ulong_t idx, ulong_t matchidx)
+{
+ int ret;
+ ctf_funcinfo_t fip;
+ ctf_id_t *args = NULL;
+
+ if (ctf_func_info(cdp->cd_ctfp, matchidx, &fip) == CTF_ERR) {
+ if (ctf_errno(cdp->cd_ctfp) == ECTF_NOFUNCDAT)
+ return (0);
+ else
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ if (fip.ctc_argc != 0) {
+ args = ctf_alloc(sizeof (ctf_id_t) * fip.ctc_argc);
+ if (args == NULL)
+ return (ENOMEM);
+
+ if (ctf_func_args(cdp->cd_ctfp, matchidx, fip.ctc_argc, args) ==
+ CTF_ERR) {
+ ctf_free(args, sizeof (ctf_id_t) * fip.ctc_argc);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ }
+
+ ret = ctf_add_function(cdp->cd_ctfp, idx, &fip, args);
+ if (args != NULL)
+ ctf_free(args, sizeof (ctf_id_t) * fip.ctc_argc);
+ if (ret == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_weaks_cb(ctf_die_t *cdp, const GElf_Sym *symp,
+ ulong_t idx, const char *file, const char *name, void *arg)
+{
+ int ret, type;
+ ctf_dwarf_weak_arg_t cweak;
+
+ /*
+ * We only care about weak symbols.
+ */
+ if (GELF_ST_BIND(symp->st_info) != STB_WEAK)
+ return (0);
+
+ type = GELF_ST_TYPE(symp->st_info);
+ ASSERT(type == STT_OBJECT || type == STT_FUNC);
+
+ /*
+ * For each weak symbol we encounter, we need to do a second iteration
+ * to try and find a match. We should probably think about other
+ * techniques to try and save us time in the future.
+ */
+ cweak.cweak_symp = symp;
+ cweak.cweak_file = file;
+ cweak.cweak_candidate = B_FALSE;
+ cweak.cweak_idx = 0;
+
+ ctf_dprintf("Trying to find weak equiv for %s\n", name);
+
+ ret = ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_check_weak, &cweak);
+ VERIFY(ret == 0 || ret == 1);
+
+ /*
+ * Nothing was ever found, we're not going to add anything for this
+ * entry.
+ */
+ if (ret == 0 && cweak.cweak_candidate == B_FALSE) {
+ ctf_dprintf("found no weak match for %s\n", name);
+ return (0);
+ }
+
+ /*
+ * Now, finally go and add the type based on the match.
+ */
+ if (type == STT_OBJECT) {
+ ret = ctf_dwarf_duplicate_sym(cdp, idx, cweak.cweak_idx);
+ } else {
+ ret = ctf_dwarf_duplicate_func(cdp, idx, cweak.cweak_idx);
+ }
+
+ return (ret);
+}
+
+static int
+ctf_dwarf_conv_weaks(ctf_die_t *cdp)
+{
+ return (ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_weaks_cb, NULL));
+}
+
+/* ARGSUSED */
+static int
+ctf_dwarf_convert_one(void *arg, void *unused)
+{
+ int ret;
+ ctf_file_t *dedup;
+ ctf_die_t *cdp = arg;
+
+ ctf_dprintf("converting die: %s\n", cdp->cd_name);
+ ctf_dprintf("max offset: %x\n", cdp->cd_maxoff);
+ VERIFY(cdp != NULL);
+
+ ret = ctf_dwarf_convert_die(cdp, cdp->cd_cu);
+ ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ ret = ctf_dwarf_fixup_die(cdp, B_FALSE);
+ ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ ret = ctf_dwarf_fixup_die(cdp, B_TRUE);
+ ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+
+ if ((ret = ctf_dwarf_conv_funcvars(cdp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to convert strong functions and variables"));
+ }
+
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ if (cdp->cd_doweaks == B_TRUE) {
+ if ((ret = ctf_dwarf_conv_weaks(cdp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to convert weak functions and variables"));
+ }
+
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+ }
+
+ ctf_phase_dump(cdp->cd_ctfp, "pre-dedup");
+ ctf_dprintf("adding inputs for dedup\n");
+ if ((ret = ctf_merge_add(cdp->cd_cmh, cdp->cd_ctfp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to add inputs for merge"));
+ }
+
+ ctf_dprintf("starting merge\n");
+ if ((ret = ctf_merge_dedup(cdp->cd_cmh, &dedup)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to deduplicate die"));
+ }
+ ctf_close(cdp->cd_ctfp);
+ cdp->cd_ctfp = dedup;
+
+ return (0);
+}
+
+/*
+ * Note, we expect that if we're returning a ctf_file_t from one of the dies,
+ * say in the single node case, it's been saved and the entry here has been set
+ * to NULL, which ctf_close happily ignores.
+ */
+static void
+ctf_dwarf_free_die(ctf_die_t *cdp)
+{
+ ctf_dwfunc_t *cdf, *ndf;
+ ctf_dwvar_t *cdv, *ndv;
+ ctf_dwbitf_t *cdb, *ndb;
+ ctf_dwmap_t *map;
+ void *cookie;
+ Dwarf_Error derr;
+
+ ctf_dprintf("Beginning to free die: %p\n", cdp);
+ cdp->cd_elf = NULL;
+ ctf_dprintf("Trying to free name: %p\n", cdp->cd_name);
+ if (cdp->cd_name != NULL)
+ ctf_free(cdp->cd_name, strlen(cdp->cd_name) + 1);
+ ctf_dprintf("Trying to free merge handle: %p\n", cdp->cd_cmh);
+ if (cdp->cd_cmh != NULL) {
+ ctf_merge_fini(cdp->cd_cmh);
+ cdp->cd_cmh = NULL;
+ }
+
+ ctf_dprintf("Trying to free functions\n");
+ for (cdf = ctf_list_next(&cdp->cd_funcs); cdf != NULL; cdf = ndf) {
+ ndf = ctf_list_next(cdf);
+ ctf_free(cdf->cdf_name, strlen(cdf->cdf_name) + 1);
+ if (cdf->cdf_fip.ctc_argc != 0) {
+ ctf_free(cdf->cdf_argv,
+ sizeof (ctf_id_t) * cdf->cdf_fip.ctc_argc);
+ }
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ }
+
+ ctf_dprintf("Trying to free variables\n");
+ for (cdv = ctf_list_next(&cdp->cd_vars); cdv != NULL; cdv = ndv) {
+ ndv = ctf_list_next(cdv);
+ ctf_free(cdv->cdv_name, strlen(cdv->cdv_name) + 1);
+ ctf_free(cdv, sizeof (ctf_dwvar_t));
+ }
+
+ ctf_dprintf("Trying to free bitfields\n");
+ for (cdb = ctf_list_next(&cdp->cd_bitfields); cdb != NULL; cdb = ndb) {
+ ndb = ctf_list_next(cdb);
+ ctf_free(cdb, sizeof (ctf_dwbitf_t));
+ }
+
+ /* How do we clean up die usage? */
+ ctf_dprintf("Trying to clean up dwarf_t: %p\n", cdp->cd_dwarf);
+ (void) dwarf_finish(cdp->cd_dwarf, &derr);
+ cdp->cd_dwarf = NULL;
+ ctf_close(cdp->cd_ctfp);
+
+ cookie = NULL;
+ while ((map = avl_destroy_nodes(&cdp->cd_map, &cookie)) != NULL) {
+ ctf_free(map, sizeof (ctf_dwmap_t));
+ }
+ avl_destroy(&cdp->cd_map);
+ cdp->cd_errbuf = NULL;
+}
+
+static void
+ctf_dwarf_free_dies(ctf_die_t *cdies, int ndies)
+{
+ int i;
+
+ ctf_dprintf("Beginning to free dies\n");
+ for (i = 0; i < ndies; i++) {
+ ctf_dwarf_free_die(&cdies[i]);
+ }
+
+ ctf_free(cdies, sizeof (ctf_die_t) * ndies);
+}
+
+static int
+ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
+ char *errbuf, size_t errlen)
+{
+ int ret;
+ Dwarf_Half vers;
+ Dwarf_Unsigned nexthdr;
+
+ while ((ret = dwarf_next_cu_header(dw, NULL, &vers, NULL, NULL,
+ &nexthdr, derr)) != DW_DLV_NO_ENTRY) {
+ if (ret != DW_DLV_OK) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain valid DWARF data: %s\n",
+ dwarf_errmsg(*derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ if (vers != DWARF_VERSION_TWO) {
+ (void) snprintf(errbuf, errlen,
+ "unsupported DWARF version: %d\n", vers);
+ return (ECTF_CONVBKERR);
+ }
+ *ndies = *ndies + 1;
+ }
+
+ if (*ndies == 0) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain valid DWARF data: %s\n",
+ dwarf_errmsg(*derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+/*
+ * Iterate over all of the dies and create a ctf_die_t for each of them. This is
+ * used to determine if we have zero, one, or multiple dies to convert. If we
+ * have zero, that's an error. If there's only one die, that's the simple case.
+ * No merge needed and only a single Dwarf_Debug as well.
+ */
+static int
+ctf_dwarf_init_die(int fd, Elf *elf, ctf_die_t *cdp, int ndie, char *errbuf,
+ size_t errlen)
+{
+ int ret;
+ Dwarf_Unsigned hdrlen, abboff, nexthdr;
+ Dwarf_Half addrsz;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Error derr;
+
+ while ((ret = dwarf_next_cu_header(cdp->cd_dwarf, &hdrlen, NULL,
+ &abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) {
+ char *name;
+ Dwarf_Die cu, child;
+
+ /* Based on the counting above, we should be good to go */
+ VERIFY(ret == DW_DLV_OK);
+ if (ndie > 0) {
+ ndie--;
+ offset = nexthdr;
+ continue;
+ }
+
+ /*
+ * Compilers are apparently inconsistent. Some emit no DWARF for
+ * empty files and others emit empty compilation unit.
+ */
+ cdp->cd_voidtid = CTF_ERR;
+ cdp->cd_longtid = CTF_ERR;
+ cdp->cd_elf = elf;
+ cdp->cd_maxoff = nexthdr - 1;
+ cdp->cd_ctfp = ctf_fdcreate(fd, &ret);
+ if (cdp->cd_ctfp == NULL) {
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ avl_create(&cdp->cd_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t),
+ offsetof(ctf_dwmap_t, cdm_avl));
+ cdp->cd_errbuf = errbuf;
+ cdp->cd_errlen = errlen;
+ bzero(&cdp->cd_vars, sizeof (ctf_list_t));
+ bzero(&cdp->cd_funcs, sizeof (ctf_list_t));
+ bzero(&cdp->cd_bitfields, sizeof (ctf_list_t));
+
+ if ((ret = ctf_dwarf_die_elfenc(elf, cdp, errbuf,
+ errlen)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_sib(cdp, NULL, &cu)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ if (cu == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ECTF_CONVBKERR);
+ }
+
+ if ((ret = ctf_dwarf_child(cdp, cu, &child)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ if (child == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ECTF_CONVBKERR);
+ }
+
+ cdp->cd_cuoff = offset;
+ cdp->cd_cu = child;
+
+ if ((cdp->cd_cmh = ctf_merge_init(fd, &ret)) == NULL) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+
+ if (ctf_dwarf_string(cdp, cu, DW_AT_name, &name) == 0) {
+ size_t len = strlen(name) + 1;
+ char *b = basename(name);
+ cdp->cd_name = strdup(b);
+ ctf_free(name, len);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+
+ctf_conv_status_t
+ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
+ char *errmsg, size_t errlen)
+{
+ int err, ret, ndies, i;
+ Dwarf_Debug dw;
+ Dwarf_Error derr;
+ ctf_die_t *cdies = NULL, *cdp;
+ workq_t *wqp = NULL;
+
+ if (errp == NULL)
+ errp = &err;
+ *errp = 0;
+ *fpp = NULL;
+
+ ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw, &derr);
+ if (ret != DW_DLV_OK) {
+ /*
+ * The old CTF tools used to check if we expected DWARF data
+ * here. In this case, if we actually have some amount of DWARF,
+ * but no section, for now, just go ahead and create an empty
+ * CTF file.
+ */
+ if (ret == DW_DLV_NO_ENTRY ||
+ dwarf_errno(derr) == DW_DLE_DEBUG_INFO_NULL) {
+ *fpp = ctf_create(errp);
+ return (*fpp != NULL ? CTF_CONV_SUCCESS :
+ CTF_CONV_ERROR);
+ }
+ (void) snprintf(errmsg, errlen,
+ "failed to initialize DWARF: %s\n",
+ dwarf_errmsg(derr));
+ *errp = ECTF_CONVBKERR;
+ return (CTF_CONV_ERROR);
+ }
+
+ ndies = 0;
+ ret = ctf_dwarf_count_dies(dw, &derr, &ndies, errmsg, errlen);
+ if (ret != 0) {
+ *errp = ret;
+ goto out;
+ }
+
+ (void) dwarf_finish(dw, &derr);
+ cdies = ctf_alloc(sizeof (ctf_die_t) * ndies);
+ if (cdies == NULL) {
+ *errp = ENOMEM;
+ return (CTF_CONV_ERROR);
+ }
+
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL,
+ &cdp->cd_dwarf, &derr);
+ if (ret != 0) {
+ ctf_free(cdies, sizeof (ctf_die_t) * ndies);
+ (void) snprintf(errmsg, errlen,
+ "failed to initialize DWARF: %s\n",
+ dwarf_errmsg(derr));
+ *errp = ECTF_CONVBKERR;
+ return (CTF_CONV_ERROR);
+ }
+
+ ret = ctf_dwarf_init_die(fd, elf, &cdies[i], i, errmsg, errlen);
+ if (ret != 0) {
+ *errp = ret;
+ goto out;
+ }
+ cdp->cd_doweaks = ndies > 1 ? B_FALSE : B_TRUE;
+ }
+
+ ctf_dprintf("found %d DWARF die(s)\n", ndies);
+
+ /*
+ * If we only have one die, there's no reason to use multiple threads,
+ * even if the user requested them. After all, they just gave us an
+ * upper bound.
+ */
+ if (ndies == 1)
+ nthrs = 1;
+
+ if (workq_init(&wqp, nthrs) == -1) {
+ *errp = errno;
+ goto out;
+ }
+
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ ctf_dprintf("adding die %s: %p, %x %x\n", cdp->cd_name,
+ cdp->cd_cu, cdp->cd_cuoff, cdp->cd_maxoff);
+ if (workq_add(wqp, cdp) == -1) {
+ *errp = errno;
+ goto out;
+ }
+ }
+
+ ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, errp);
+ if (ret == WORKQ_ERROR) {
+ *errp = errno;
+ goto out;
+ } else if (ret == WORKQ_UERROR) {
+ ctf_dprintf("internal convert failed: %s\n",
+ ctf_errmsg(*errp));
+ goto out;
+ }
+
+ ctf_dprintf("Determining next phase: have %d dies\n", ndies);
+ if (ndies != 1) {
+ ctf_merge_t *cmp;
+
+ cmp = ctf_merge_init(fd, &ret);
+ if (cmp == NULL) {
+ *errp = ret;
+ goto out;
+ }
+
+ ctf_dprintf("setting threads\n");
+ if ((ret = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+
+ ctf_dprintf("adding dies\n");
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ if ((ret = ctf_merge_add(cmp, cdp->cd_ctfp)) != 0) {
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+ }
+
+ ctf_dprintf("performing merge\n");
+ ret = ctf_merge_merge(cmp, fpp);
+ if (ret != 0) {
+ ctf_dprintf("failed merge!\n");
+ *fpp = NULL;
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+ ctf_merge_fini(cmp);
+ *errp = 0;
+ ctf_dprintf("successfully converted!\n");
+ } else {
+ *errp = 0;
+ *fpp = cdies->cd_ctfp;
+ cdies->cd_ctfp = NULL;
+ ctf_dprintf("successfully converted!\n");
+ }
+
+out:
+ workq_fini(wqp);
+ ctf_dwarf_free_dies(cdies, ndies);
+ return (*fpp != NULL ? CTF_CONV_SUCCESS : CTF_CONV_ERROR);
+}
diff --git a/usr/src/lib/libctf/common/ctf_elfwrite.c b/usr/src/lib/libctf/common/ctf_elfwrite.c
new file mode 100644
index 0000000000..4d7c10aeec
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_elfwrite.c
@@ -0,0 +1,422 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2015, Joyent, Inc.
+ */
+
+/*
+ * Routines for writing ctf data to elf files, originally from the ctf tools.
+ */
+
+#include <libctf_impl.h>
+#include <libctf.h>
+#include <gelf.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libelf.h>
+
+static int
+ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
+{
+ GElf_Ehdr sehdr, dehdr;
+ Elf_Scn *sscn, *dscn;
+ Elf_Data *sdata, *ddata;
+ GElf_Shdr shdr;
+ int symtab_idx = -1;
+ off_t new_offset = 0;
+ off_t ctfnameoff = 0;
+ int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
+ int *secxlate = NULL;
+ int srcidx, dstidx, pad, i;
+ int curnmoff = 0;
+ int changing = 0;
+ int ret;
+ size_t nshdr, nphdr, strndx;
+ void *strdatabuf = NULL, *symdatabuf = NULL;
+ size_t strdatasz = 0, symdatasz = 0;
+
+ void *cdata = NULL;
+ size_t elfsize, asize;
+
+ if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
+ ret = ctf_set_errno(fp, EINVAL);
+ goto out;
+ }
+
+ if (gelf_newehdr(dst, gelf_getclass(src)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (gelf_getehdr(src, &sehdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ (void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
+ if (gelf_update_ehdr(dst, &dehdr) == 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ /*
+ * Use libelf to get the number of sections and the string section to
+ * deal with ELF files that may have a large number of sections. We just
+ * always use this to make our live easier.
+ */
+ if (elf_getphdrnum(src, &nphdr) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (elf_getshdrnum(src, &nshdr) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (elf_getshdrstrndx(src, &strndx) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ /*
+ * Neither the existing debug sections nor the SUNW_ctf sections (new or
+ * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
+ * program headers. As such, we can just blindly copy the program
+ * headers from the existing file to the new file.
+ */
+ if (nphdr != 0) {
+ (void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
+ if (gelf_newphdr(dst, nphdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ for (i = 0; i < nphdr; i++) {
+ GElf_Phdr phdr;
+
+ if (gelf_getphdr(src, i, &phdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (gelf_update_phdr(dst, i, &phdr) == 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ }
+ }
+
+ secxlate = ctf_alloc(sizeof (int) * nshdr);
+ for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) {
+ Elf_Scn *scn = elf_getscn(src, srcidx);
+ GElf_Shdr shdr;
+ char *sname;
+
+ if (gelf_getshdr(scn, &shdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ sname = elf_strptr(src, strndx, shdr.sh_name);
+ if (sname == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
+ secxlate[srcidx] = -1;
+ } else {
+ secxlate[srcidx] = dstidx++;
+ curnmoff += strlen(sname) + 1;
+ }
+
+ new_offset = (off_t)dehdr.e_phoff;
+ }
+
+ for (srcidx = 1; srcidx < nshdr; srcidx++) {
+ char *sname;
+
+ sscn = elf_getscn(src, srcidx);
+ if (gelf_getshdr(sscn, &shdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ if (secxlate[srcidx] == -1) {
+ changing = 1;
+ continue;
+ }
+
+ dscn = elf_newscn(dst);
+ if (dscn == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ /*
+ * If this file has program headers, we need to explicitly lay
+ * out sections. If none of the sections prior to this one have
+ * been removed, then we can just use the existing location. If
+ * one or more sections have been changed, then we need to
+ * adjust this one to avoid holes.
+ */
+ if (changing && nphdr != 0) {
+ pad = new_offset % shdr.sh_addralign;
+
+ if (pad != 0)
+ new_offset += shdr.sh_addralign - pad;
+ shdr.sh_offset = new_offset;
+ }
+
+ shdr.sh_link = secxlate[shdr.sh_link];
+
+ if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
+ shdr.sh_info = secxlate[shdr.sh_info];
+
+ sname = elf_strptr(src, strndx, shdr.sh_name);
+ if (sname == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if ((ddata = elf_newdata(dscn)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ bcopy(sdata, ddata, sizeof (Elf_Data));
+
+ if (srcidx == strndx) {
+ char seclen = strlen(CTF_ELF_SCN_NAME);
+
+ strdatasz = ddata->d_size + shdr.sh_size +
+ seclen + 1;
+ ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
+ if (ddata->d_buf == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
+ (void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
+ CTF_ELF_SCN_NAME);
+ ctfnameoff = (off_t)shdr.sh_size;
+ shdr.sh_size += seclen + 1;
+ ddata->d_size += seclen + 1;
+
+ if (nphdr != 0)
+ changing = 1;
+ }
+
+ if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
+ int nsym = shdr.sh_size / shdr.sh_entsize;
+
+ symtab_idx = secxlate[srcidx];
+
+ symdatasz = shdr.sh_size;
+ ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
+ if (ddata->d_buf == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ (void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
+
+ for (i = 0; i < nsym; i++) {
+ GElf_Sym sym;
+ short newscn;
+
+ (void) gelf_getsym(ddata, i, &sym);
+
+ if (sym.st_shndx >= SHN_LORESERVE)
+ continue;
+
+ if ((newscn = secxlate[sym.st_shndx]) !=
+ sym.st_shndx) {
+ sym.st_shndx =
+ (newscn == -1 ? 1 : newscn);
+
+ if (gelf_update_sym(ddata, i, &sym) ==
+ 0) {
+ ret = ctf_set_errno(fp,
+ ECTF_ELF);
+ goto out;
+ }
+ }
+ }
+ }
+
+ if (gelf_update_shdr(dscn, &shdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ new_offset = (off_t)shdr.sh_offset;
+ if (shdr.sh_type != SHT_NOBITS)
+ new_offset += shdr.sh_size;
+ }
+
+ if (symtab_idx == -1) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ /* Add the ctf section */
+ if ((dscn = elf_newscn(dst)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (gelf_getshdr(dscn, &shdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ shdr.sh_name = ctfnameoff;
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_size = fp->ctf_size;
+ shdr.sh_link = symtab_idx;
+ shdr.sh_addralign = 4;
+ if (changing && nphdr != 0) {
+ pad = new_offset % shdr.sh_addralign;
+
+ if (pad)
+ new_offset += shdr.sh_addralign - pad;
+
+ shdr.sh_offset = new_offset;
+ new_offset += shdr.sh_size;
+ }
+
+ if ((ddata = elf_newdata(dscn)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ if (compress != 0) {
+ int err;
+
+ if (ctf_zopen(&err) == NULL) {
+ ret = ctf_set_errno(fp, err);
+ goto out;
+ }
+
+ if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
+ ret = ctf_set_errno(fp, err);
+ goto out;
+ }
+ ddata->d_buf = cdata;
+ ddata->d_size = elfsize;
+ } else {
+ ddata->d_buf = (void *)fp->ctf_base;
+ ddata->d_size = fp->ctf_size;
+ }
+ ddata->d_align = shdr.sh_addralign;
+
+ if (gelf_update_shdr(dscn, &shdr) == 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ /* update the section header location */
+ if (nphdr != 0) {
+ size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
+ size_t r = new_offset % align;
+
+ if (r)
+ new_offset += align - r;
+
+ dehdr.e_shoff = new_offset;
+ }
+
+ /* commit to disk */
+ if (sehdr.e_shstrndx == SHN_XINDEX)
+ dehdr.e_shstrndx = SHN_XINDEX;
+ else
+ dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
+ if (gelf_update_ehdr(dst, &dehdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (elf_update(dst, ELF_C_WRITE) < 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if (strdatabuf != NULL)
+ ctf_free(strdatabuf, strdatasz);
+ if (symdatabuf != NULL)
+ ctf_free(symdatabuf, symdatasz);
+ if (cdata != NULL)
+ ctf_data_free(cdata, fp->ctf_size);
+ if (secxlate != NULL)
+ ctf_free(secxlate, sizeof (int) * nshdr);
+
+ return (ret);
+}
+
+int
+ctf_elffdwrite(ctf_file_t *fp, int ifd, int ofd, int flags)
+{
+ int ret;
+ Elf *ielf, *oelf;
+
+ (void) elf_version(EV_CURRENT);
+ if ((ielf = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
+ return (ctf_set_errno(fp, ECTF_ELF));
+
+ if ((oelf = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL)
+ return (ctf_set_errno(fp, ECTF_ELF));
+
+ ret = ctf_write_elf(fp, ielf, oelf, flags);
+
+ (void) elf_end(ielf);
+ (void) elf_end(oelf);
+
+ return (ret);
+}
+
+int
+ctf_elfwrite(ctf_file_t *fp, const char *input, const char *output, int flags)
+{
+ struct stat st;
+ int ifd, ofd, ret;
+
+ if ((ifd = open(input, O_RDONLY)) < 0)
+ return (ctf_set_errno(fp, errno));
+
+ if (fstat(ifd, &st) < 0)
+ return (ctf_set_errno(fp, errno));
+
+ if ((ofd = open(output, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
+ return (ctf_set_errno(fp, errno));
+
+ ret = ctf_elffdwrite(fp, ifd, ofd, flags);
+
+ if (close(ifd) != 0 && ret != 0)
+ ret = ctf_set_errno(fp, errno);
+ if (close(ofd) != 0 && ret != 0)
+ ret = ctf_set_errno(fp, errno);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c
index e71ebc6d9d..6b637ba663 100644
--- a/usr/src/lib/libctf/common/ctf_lib.c
+++ b/usr/src/lib/libctf/common/ctf_lib.c
@@ -23,6 +23,9 @@
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2015, Joyent, Inc.
+ */
#include <sys/types.h>
#include <sys/stat.h>
@@ -33,6 +36,9 @@
#include <errno.h>
#include <dlfcn.h>
#include <gelf.h>
+#include <zlib.h>
+#include <zone.h>
+#include <sys/debug.h>
#ifdef _LP64
static const char *_libctf_zlib = "/usr/lib/64/libz.so.1";
@@ -42,6 +48,9 @@ static const char *_libctf_zlib = "/usr/lib/libz.so.1";
static struct {
int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
+ int (*z_initcomp)(z_stream *, int, const char *, int);
+ int (*z_compress)(z_stream *, int);
+ int (*z_finicomp)(z_stream *);
const char *(*z_error)(int);
void *z_dlp;
} zlib;
@@ -49,6 +58,18 @@ static struct {
static size_t _PAGESIZE;
static size_t _PAGEMASK;
+static uint64_t ctf_phase = 0;
+
+#define CTF_COMPRESS_CHUNK (64*1024)
+
+typedef struct ctf_zdata {
+ void *czd_buf;
+ void *czd_next;
+ ctf_file_t *czd_ctfp;
+ size_t czd_allocsz;
+ z_stream czd_zstr;
+} ctf_zdata_t;
+
#pragma init(_libctf_init)
void
_libctf_init(void)
@@ -72,21 +93,47 @@ _libctf_init(void)
void *
ctf_zopen(int *errp)
{
- ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
+ char buf[MAXPATHLEN];
+ const char *path = _libctf_zlib, *zroot;
if (zlib.z_dlp != NULL)
return (zlib.z_dlp); /* library is already loaded */
- if (access(_libctf_zlib, R_OK) == -1)
+ /*
+ * Get the zone native root. For the tools build, we don't need
+ * this (it seems fair to impose that we always build the system in
+ * a native zone), and we want to allow build machines that are older
+ * that the notion of the native root, so we only actually make this
+ * call if we're not the tools build.
+ */
+#ifndef CTF_TOOLS_BUILD
+ zroot = zone_get_nroot();
+#else
+ zroot = NULL;
+#endif
+
+ if (zroot != NULL) {
+ (void) snprintf(buf, MAXPATHLEN, "%s/%s", zroot, _libctf_zlib);
+ path = buf;
+ }
+
+ ctf_dprintf("decompressing CTF data using %s\n", path);
+
+ if (access(path, R_OK) == -1)
return (ctf_set_open_errno(errp, ECTF_ZMISSING));
- if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
+ if ((zlib.z_dlp = dlopen(path, RTLD_LAZY | RTLD_LOCAL)) == NULL)
return (ctf_set_open_errno(errp, ECTF_ZINIT));
zlib.z_uncompress = (int (*)()) dlsym(zlib.z_dlp, "uncompress");
+ zlib.z_initcomp = (int (*)()) dlsym(zlib.z_dlp, "deflateInit_");
+ zlib.z_compress = (int (*)()) dlsym(zlib.z_dlp, "deflate");
+ zlib.z_finicomp = (int (*)()) dlsym(zlib.z_dlp, "deflateEnd");
zlib.z_error = (const char *(*)()) dlsym(zlib.z_dlp, "zError");
- if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
+ if (zlib.z_uncompress == NULL || zlib.z_error == NULL ||
+ zlib.z_initcomp == NULL|| zlib.z_compress == NULL ||
+ zlib.z_finicomp == NULL) {
(void) dlclose(zlib.z_dlp);
bzero(&zlib, sizeof (zlib));
return (ctf_set_open_errno(errp, ECTF_ZINIT));
@@ -111,6 +158,207 @@ z_strerror(int err)
return (zlib.z_error(err));
}
+static int
+ctf_zdata_init(ctf_zdata_t *czd, ctf_file_t *fp)
+{
+ int err;
+ ctf_header_t *cthp;
+
+ bzero(czd, sizeof (ctf_zdata_t));
+
+ czd->czd_allocsz = fp->ctf_size;
+ czd->czd_buf = ctf_data_alloc(czd->czd_allocsz);
+ if (czd->czd_buf == MAP_FAILED)
+ return (ctf_set_errno(fp, ENOMEM));
+
+ bcopy(fp->ctf_base, czd->czd_buf, sizeof (ctf_header_t));
+ czd->czd_ctfp = fp;
+ cthp = czd->czd_buf;
+ cthp->cth_flags |= CTF_F_COMPRESS;
+ czd->czd_next = (void *)((uintptr_t)czd->czd_buf +
+ sizeof (ctf_header_t));
+
+ if ((err = zlib.z_initcomp(&czd->czd_zstr, Z_BEST_COMPRESSION,
+ ZLIB_VERSION, sizeof (z_stream))) != Z_OK)
+ return (ctf_set_errno(fp, ECTF_ZLIB));
+
+ return (0);
+}
+
+static int
+ctf_zdata_grow(ctf_zdata_t *czd)
+{
+ size_t off;
+ size_t newsz;
+ void *ndata;
+
+ off = (uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf;
+ newsz = czd->czd_allocsz + CTF_COMPRESS_CHUNK;
+ ndata = ctf_data_alloc(newsz);
+ if (ndata == MAP_FAILED) {
+ return (ctf_set_errno(czd->czd_ctfp, ENOMEM));
+ }
+
+ bcopy(czd->czd_buf, ndata, off);
+ ctf_data_free(czd->czd_buf, czd->czd_allocsz);
+ czd->czd_allocsz = newsz;
+ czd->czd_buf = ndata;
+ czd->czd_next = (void *)((uintptr_t)ndata + off);
+
+ czd->czd_zstr.next_out = (Bytef *)czd->czd_next;
+ czd->czd_zstr.avail_out = CTF_COMPRESS_CHUNK;
+ return (0);
+}
+
+static int
+ctf_zdata_compress_buffer(ctf_zdata_t *czd, const void *buf, size_t bufsize)
+{
+ int err;
+
+ czd->czd_zstr.next_out = czd->czd_next;
+ czd->czd_zstr.avail_out = czd->czd_allocsz -
+ (czd->czd_next - czd->czd_buf);
+ czd->czd_zstr.next_in = (Bytef *)buf;
+ czd->czd_zstr.avail_in = bufsize;
+
+ while (czd->czd_zstr.avail_in != 0) {
+ if (czd->czd_zstr.avail_out == 0) {
+ czd->czd_next = czd->czd_zstr.next_out;
+ if ((err = ctf_zdata_grow(czd)) != 0) {
+ return (err);
+ }
+ }
+
+ if ((err = zlib.z_compress(&czd->czd_zstr, Z_NO_FLUSH)) != Z_OK)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+ }
+ czd->czd_next = czd->czd_zstr.next_out;
+
+ return (0);
+}
+
+static int
+ctf_zdata_flush(ctf_zdata_t *czd, boolean_t finish)
+{
+ int err;
+ int flag = finish == B_TRUE ? Z_FINISH : Z_FULL_FLUSH;
+ int bret = finish == B_TRUE ? Z_STREAM_END : Z_BUF_ERROR;
+
+ for (;;) {
+ if (czd->czd_zstr.avail_out == 0) {
+ czd->czd_next = czd->czd_zstr.next_out;
+ if ((err = ctf_zdata_grow(czd)) != 0) {
+ return (err);
+ }
+ }
+
+ err = zlib.z_compress(&czd->czd_zstr, flag);
+ if (err == bret) {
+ break;
+ }
+ if (err != Z_OK)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+
+ }
+
+ czd->czd_next = czd->czd_zstr.next_out;
+
+ return (0);
+}
+
+static int
+ctf_zdata_end(ctf_zdata_t *czd)
+{
+ int ret;
+
+ if ((ret = ctf_zdata_flush(czd, B_TRUE)) != 0)
+ return (ret);
+
+ if ((ret = zlib.z_finicomp(&czd->czd_zstr)) != 0)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+
+ return (0);
+}
+
+static void
+ctf_zdata_cleanup(ctf_zdata_t *czd)
+{
+ ctf_data_free(czd->czd_buf, czd->czd_allocsz);
+ (void) zlib.z_finicomp(&czd->czd_zstr);
+}
+
+/*
+ * Compress our CTF data and return both the size of the compressed data and the
+ * size of the allocation. These may be different due to the nature of
+ * compression.
+ *
+ * In addition, we flush the compression inbetween our two phases such that we
+ * maintain a different dictionary bbetween the CTF data and the string section.
+ */
+int
+ctf_compress(ctf_file_t *fp, void **buf, size_t *allocsz, size_t *elfsize)
+{
+ int err;
+ ctf_zdata_t czd;
+ ctf_header_t *cthp = (ctf_header_t *)fp->ctf_base;
+
+ if ((err = ctf_zdata_init(&czd, fp)) != 0)
+ return (err);
+
+ if ((err = ctf_zdata_compress_buffer(&czd, fp->ctf_buf,
+ cthp->cth_stroff)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_flush(&czd, B_FALSE)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_compress_buffer(&czd,
+ fp->ctf_buf + cthp->cth_stroff, cthp->cth_strlen)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_end(&czd)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ *buf = czd.czd_buf;
+ *allocsz = czd.czd_allocsz;
+ *elfsize = (uintptr_t)(czd.czd_next - czd.czd_buf);
+
+ return (0);
+}
+
+int
+z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen)
+{
+ z_stream zs;
+ int err;
+
+ bzero(&zs, sizeof (z_stream));
+ zs.next_in = (uchar_t *)src;
+ zs.avail_in = srclen;
+ zs.next_out = dst;
+ zs.avail_out = *dstlen;
+
+ if ((err = zlib.z_initcomp(&zs, Z_BEST_COMPRESSION, ZLIB_VERSION,
+ sizeof (z_stream))) != Z_OK)
+ return (err);
+
+ if ((err = zlib.z_compress(&zs, Z_FINISH)) != Z_STREAM_END) {
+ (void) zlib.z_finicomp(&zs);
+ return (err == Z_OK ? Z_BUF_ERROR : err);
+ }
+
+ *dstlen = zs.total_out;
+ return (zlib.z_finicomp(&zs));
+}
+
/*
* Convert a 32-bit ELF file header into GElf.
*/
@@ -189,7 +437,7 @@ ctf_sect_munmap(const ctf_sect_t *sp)
* responsible for closing the file descriptor when it is no longer needed.
*/
ctf_file_t *
-ctf_fdopen(int fd, int *errp)
+ctf_fdcreate_int(int fd, int *errp, ctf_sect_t *ctfp)
{
ctf_sect_t ctfsect, symsect, strsect;
ctf_file_t *fp = NULL;
@@ -221,6 +469,9 @@ ctf_fdopen(int fd, int *errp)
*/
if (nbytes >= sizeof (ctf_preamble_t) &&
hdr.ctf.ctp_magic == CTF_MAGIC) {
+ if (ctfp != NULL)
+ return (ctf_set_open_errno(errp, EINVAL));
+
if (hdr.ctf.ctp_version > CTF_VERSION)
return (ctf_set_open_errno(errp, ECTF_CTFVERS));
@@ -370,7 +621,8 @@ ctf_fdopen(int fd, int *errp)
continue; /* corrupt sh_name field */
if (shp->sh_type == SHT_PROGBITS &&
- strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
+ strcmp(strs + shp->sh_name, _CTF_SECTION) == 0 &&
+ ctfp == NULL) {
ctfsect.cts_name = strs + shp->sh_name;
ctfsect.cts_type = shp->sh_type;
ctfsect.cts_flags = shp->sh_flags;
@@ -397,18 +649,22 @@ ctf_fdopen(int fd, int *errp)
free(sp); /* free section header array */
- if (ctfsect.cts_type == SHT_NULL) {
- (void) munmap(strs_map, strs_mapsz);
- return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
- }
+ if (ctfp == NULL) {
+ if (ctfsect.cts_type == SHT_NULL && ctfp == NULL) {
+ (void) munmap(strs_map, strs_mapsz);
+ return (ctf_set_open_errno(errp,
+ ECTF_NOCTFDATA));
+ }
- /*
- * Now mmap the CTF data, symtab, and strtab sections and
- * call ctf_bufopen() to do the rest of the work.
- */
- if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
- (void) munmap(strs_map, strs_mapsz);
- return (ctf_set_open_errno(errp, ECTF_MMAP));
+ /*
+ * Now mmap the CTF data, symtab, and strtab sections
+ * and call ctf_bufopen() to do the rest of the work.
+ */
+ if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
+ (void) munmap(strs_map, strs_mapsz);
+ return (ctf_set_open_errno(errp, ECTF_MMAP));
+ }
+ ctfp = &ctfsect;
}
if (symsect.cts_type != SHT_NULL &&
@@ -418,12 +674,13 @@ ctf_fdopen(int fd, int *errp)
(void) ctf_set_open_errno(errp, ECTF_MMAP);
goto bad; /* unmap all and abort */
}
- fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
+ fp = ctf_bufopen(ctfp, &symsect, &strsect, errp);
} else
- fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
+ fp = ctf_bufopen(ctfp, NULL, NULL, errp);
bad:
if (fp == NULL) {
- ctf_sect_munmap(&ctfsect);
+ if (ctfp == NULL)
+ ctf_sect_munmap(&ctfsect);
ctf_sect_munmap(&symsect);
ctf_sect_munmap(&strsect);
} else
@@ -436,6 +693,12 @@ bad:
return (ctf_set_open_errno(errp, ECTF_FMT));
}
+ctf_file_t *
+ctf_fdopen(int fd, int *errp)
+{
+ return (ctf_fdcreate_int(fd, errp, NULL));
+}
+
/*
* Open the specified file and return a pointer to a CTF container. The file
* can be either an ELF file or raw CTF file. This is just a convenient
@@ -502,3 +765,25 @@ ctf_version(int version)
return (_libctf_version);
}
+
+/*
+ * A utility function for folks debugging CTF conversion and merging.
+ */
+void
+ctf_phase_dump(ctf_file_t *fp, const char *phase)
+{
+ int fd;
+ static char *base;
+ char path[MAXPATHLEN];
+
+ if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
+ return;
+
+ (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
+ phase != NULL ? phase : "",
+ ctf_phase);
+ if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
+ return;
+ (void) ctf_write(fp, fd);
+ (void) close(fd);
+}
diff --git a/usr/src/lib/libctf/common/ctf_merge.c b/usr/src/lib/libctf/common/ctf_merge.c
new file mode 100644
index 0000000000..f23dbc232d
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_merge.c
@@ -0,0 +1,1570 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+/*
+ * To perform a merge of two CTF containers, we first diff the two containers
+ * types. For every type that's in the src container, but not in the dst
+ * container, we note it and add it to dst container. If there are any objects
+ * or functions associated with src, we go through and update the types that
+ * they refer to such that they all refer to types in the dst container.
+ *
+ * The bulk of the logic for the merge, after we've run the diff, occurs in
+ * ctf_merge_common().
+ *
+ * In terms of exported APIs, we don't really export a simple merge two
+ * containers, as the general way this is used, in something like ctfmerge(1),
+ * is to add all the containers and then let us figure out the best way to merge
+ * it. In the future we'll want to grow some control over the number of threads
+ * that we use to do this, if we end up wanting a muli-threaded merge. If we do,
+ * we should take care to do the merge in the same way every time.
+ */
+
+#include <libctf_impl.h>
+#include <sys/debug.h>
+#include <sys/list.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mergeq.h>
+#include <errno.h>
+
+typedef struct ctf_merge_tinfo {
+ uint16_t cmt_map; /* Map to the type in out */
+ boolean_t cmt_fixup;
+ boolean_t cmt_forward;
+ boolean_t cmt_missing;
+} ctf_merge_tinfo_t;
+
+/*
+ * State required for doing an individual merge of two containers.
+ */
+typedef struct ctf_merge_types {
+ ctf_file_t *cm_out; /* Output CTF file */
+ ctf_file_t *cm_src; /* Input CTF file */
+ ctf_merge_tinfo_t *cm_tmap; /* Type state information */
+ boolean_t cm_dedup; /* Are we doing a dedup? */
+ boolean_t cm_unique; /* are we doing a uniquify? */
+} ctf_merge_types_t;
+
+typedef struct ctf_merge_objmap {
+ list_node_t cmo_node;
+ const char *cmo_name; /* Symbol name */
+ ulong_t cmo_idx; /* Symbol ID */
+ ctf_id_t cmo_tid; /* Type ID */
+} ctf_merge_objmap_t;
+
+typedef struct ctf_merge_funcmap {
+ list_node_t cmf_node;
+ const char *cmf_name; /* Symbol name */
+ ulong_t cmf_idx; /* Symbol ID */
+ ctf_id_t cmf_rtid; /* Type ID */
+ uint_t cmf_flags; /* ctf_funcinfo_t ctc_flags */
+ uint_t cmf_argc; /* Number of arguments */
+ ctf_id_t cmf_args[]; /* Types of arguments */
+} ctf_merge_funcmap_t;
+
+typedef struct ctf_merge_input {
+ list_node_t cmi_node;
+ ctf_file_t *cmi_input;
+ list_t cmi_omap;
+ list_t cmi_fmap;
+ boolean_t cmi_created;
+} ctf_merge_input_t;
+
+struct ctf_merge_handle {
+ list_t cmh_inputs; /* Input list */
+ uint_t cmh_ninputs; /* Number of inputs */
+ uint_t cmh_nthreads; /* Number of threads to use */
+ ctf_file_t *cmh_unique; /* ctf to uniquify against */
+ boolean_t cmh_msyms; /* Should we merge symbols/funcs? */
+ int cmh_ofd; /* FD for output file */
+ int cmh_flags; /* Flags that control merge behavior */
+ char *cmh_label; /* Optional label */
+ char *cmh_pname; /* Parent name */
+};
+
+static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
+
+static ctf_id_t
+ctf_merge_gettype(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ if (cmp->cm_dedup == B_FALSE) {
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ return (cmp->cm_tmap[id].cmt_map);
+ }
+
+ while (cmp->cm_tmap[id].cmt_missing == B_FALSE) {
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ id = cmp->cm_tmap[id].cmt_map;
+ }
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ return (cmp->cm_tmap[id].cmt_map);
+}
+
+static void
+ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
+ ctf_id_t oid, void *arg)
+{
+ ctf_merge_types_t *cmp = arg;
+ ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
+
+ if (same == B_TRUE) {
+ if (ctf_type_kind(ifp, iid) == CTF_K_FORWARD &&
+ ctf_type_kind(ofp, oid) != CTF_K_FORWARD) {
+ VERIFY(cmt[oid].cmt_map == 0);
+
+ /*
+ * If we're uniquifying types, it's possible for the
+ * container that we're uniquifying against to have a
+ * forward which exists in the container being reduced.
+ * For example, genunix has the machcpu structure as a
+ * forward which is actually in unix and we uniquify
+ * unix against genunix. In such cases, we explicitly do
+ * not do any mapping of the forward information, lest
+ * we risk losing the real definition. Instead, mark
+ * that it's missing.
+ */
+ if (cmp->cm_unique == B_TRUE) {
+ cmt[oid].cmt_missing = B_TRUE;
+ return;
+ }
+
+ cmt[oid].cmt_map = iid;
+ cmt[oid].cmt_forward = B_TRUE;
+ ctf_dprintf("merge diff forward mapped %d->%d\n", oid,
+ iid);
+ return;
+ }
+
+ /*
+ * We could have multiple things that a given type ends up
+ * matching in the world of forwards and pointers to forwards.
+ * For now just take the first one...
+ */
+ if (cmt[oid].cmt_map != 0)
+ return;
+ cmt[oid].cmt_map = iid;
+ ctf_dprintf("merge diff mapped %d->%d\n", oid, iid);
+ } else if (ifp == cmp->cm_src) {
+ VERIFY(cmt[iid].cmt_map == 0);
+ cmt[iid].cmt_missing = B_TRUE;
+ ctf_dprintf("merge diff said %d is missing\n", iid);
+ }
+}
+
+static int
+ctf_merge_add_number(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags;
+ const ctf_type_t *tp;
+ const char *name;
+ ctf_encoding_t en;
+
+ if (ctf_type_encoding(cmp->cm_src, id, &en) != 0)
+ return (CTF_ERR);
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ ret = ctf_add_encoded(cmp->cm_out, flags, name, &en,
+ ctf_type_kind(cmp->cm_src, id));
+
+ if (ret == CTF_ERR)
+ return (ret);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+ return (0);
+}
+
+static int
+ctf_merge_add_array(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags;
+ const ctf_type_t *tp;
+ ctf_arinfo_t ar;
+
+ if (ctf_array_info(cmp->cm_src, id, &ar) == CTF_ERR)
+ return (CTF_ERR);
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ if (cmp->cm_tmap[ar.ctr_contents].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, ar.ctr_contents);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[ar.ctr_contents].cmt_map != 0);
+ }
+ ar.ctr_contents = ctf_merge_gettype(cmp, ar.ctr_contents);
+
+ if (cmp->cm_tmap[ar.ctr_index].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, ar.ctr_index);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[ar.ctr_index].cmt_map != 0);
+ }
+ ar.ctr_index = ctf_merge_gettype(cmp, ar.ctr_index);
+
+ ret = ctf_add_array(cmp->cm_out, flags, &ar);
+ if (ret == CTF_ERR)
+ return (ret);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+
+ return (0);
+}
+
+static int
+ctf_merge_add_reftype(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags;
+ const ctf_type_t *tp;
+ ctf_id_t reftype;
+ const char *name;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ reftype = ctf_type_reference(cmp->cm_src, id);
+ if (reftype == CTF_ERR)
+ return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
+
+ if (cmp->cm_tmap[reftype].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, reftype);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
+ }
+ reftype = ctf_merge_gettype(cmp, reftype);
+
+ ret = ctf_add_reftype(cmp->cm_out, flags, name, reftype,
+ ctf_type_kind(cmp->cm_src, id));
+ if (ret == CTF_ERR)
+ return (ret);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+ return (0);
+}
+
+static int
+ctf_merge_add_typedef(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags;
+ const ctf_type_t *tp;
+ const char *name;
+ ctf_id_t reftype;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ reftype = ctf_type_reference(cmp->cm_src, id);
+ if (reftype == CTF_ERR)
+ return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
+
+ if (cmp->cm_tmap[reftype].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, reftype);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
+ }
+ reftype = ctf_merge_gettype(cmp, reftype);
+
+ ret = ctf_add_typedef(cmp->cm_out, flags, name, reftype);
+ if (ret == CTF_ERR)
+ return (ret);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+ return (0);
+}
+
+typedef struct ctf_merge_enum {
+ ctf_file_t *cme_fp;
+ ctf_id_t cme_id;
+} ctf_merge_enum_t;
+
+static int
+ctf_merge_add_enumerator(const char *name, int value, void *arg)
+{
+ ctf_merge_enum_t *cmep = arg;
+
+ return (ctf_add_enumerator(cmep->cme_fp, cmep->cme_id, name, value) ==
+ CTF_ERR);
+}
+
+static int
+ctf_merge_add_enum(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int flags;
+ const ctf_type_t *tp;
+ const char *name;
+ ctf_id_t enumid;
+ ctf_merge_enum_t cme;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ enumid = ctf_add_enum(cmp->cm_out, flags, name);
+ if (enumid == CTF_ERR)
+ return (enumid);
+
+ cme.cme_fp = cmp->cm_out;
+ cme.cme_id = enumid;
+ if (ctf_enum_iter(cmp->cm_src, id, ctf_merge_add_enumerator,
+ &cme) != 0)
+ return (CTF_ERR);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = enumid;
+ return (0);
+}
+
+static int
+ctf_merge_add_func(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags, i;
+ const ctf_type_t *tp;
+ ctf_funcinfo_t ctc;
+ ctf_id_t *argv;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ if (ctf_func_info_by_id(cmp->cm_src, id, &ctc) == CTF_ERR)
+ return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
+
+ argv = ctf_alloc(sizeof (ctf_id_t) * ctc.ctc_argc);
+ if (argv == NULL)
+ return (ctf_set_errno(cmp->cm_out, ENOMEM));
+ if (ctf_func_args_by_id(cmp->cm_src, id, ctc.ctc_argc, argv) ==
+ CTF_ERR) {
+ ctf_free(argv, sizeof (ctf_id_t) * ctc.ctc_argc);
+ return (ctf_set_errno(cmp->cm_out, ctf_errno(cmp->cm_src)));
+ }
+
+ if (cmp->cm_tmap[ctc.ctc_return].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, ctc.ctc_return);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[ctc.ctc_return].cmt_map != 0);
+ }
+ ctc.ctc_return = ctf_merge_gettype(cmp, ctc.ctc_return);
+
+ for (i = 0; i < ctc.ctc_argc; i++) {
+ if (cmp->cm_tmap[argv[i]].cmt_map == 0) {
+ ret = ctf_merge_add_type(cmp, argv[i]);
+ if (ret != 0)
+ return (ret);
+ ASSERT(cmp->cm_tmap[argv[i]].cmt_map != 0);
+ }
+ argv[i] = ctf_merge_gettype(cmp, argv[i]);
+ }
+
+ ret = ctf_add_funcptr(cmp->cm_out, flags, &ctc, argv);
+ ctf_free(argv, sizeof (ctf_id_t) * ctc.ctc_argc);
+ if (ret == CTF_ERR)
+ return (ret);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+ return (0);
+}
+
+static int
+ctf_merge_add_forward(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int ret, flags;
+ const ctf_type_t *tp;
+ const char *name;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+
+ /*
+ * ctf_add_forward tries to check to see if a given forward already
+ * exists in one of its hash tables. If we're here then we know that we
+ * have a forward in a container that isn't present in another.
+ * Therefore, we choose a token hash table to satisfy the API choice
+ * here.
+ */
+ ret = ctf_add_forward(cmp->cm_out, flags, name, CTF_K_STRUCT);
+ if (ret == CTF_ERR)
+ return (CTF_ERR);
+
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = ret;
+ return (0);
+}
+
+typedef struct ctf_merge_su {
+ ctf_merge_types_t *cms_cm;
+ ctf_id_t cms_id;
+} ctf_merge_su_t;
+
+static int
+ctf_merge_add_member(const char *name, ctf_id_t type, ulong_t offset, void *arg)
+{
+ ctf_merge_su_t *cms = arg;
+
+ VERIFY(cms->cms_cm->cm_tmap[type].cmt_map != 0);
+ type = cms->cms_cm->cm_tmap[type].cmt_map;
+
+ ctf_dprintf("Trying to add member %s to %d\n", name, cms->cms_id);
+ return (ctf_add_member(cms->cms_cm->cm_out, cms->cms_id, name,
+ type, offset) == CTF_ERR);
+}
+
+/*
+ * During the first pass, we always add the generic structure and union but none
+ * of its members as they might not all have been mapped yet. Instead we just
+ * mark all structures and unions as needing to be fixed up.
+ */
+static int
+ctf_merge_add_sou(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
+{
+ int flags, kind;
+ const ctf_type_t *tp;
+ const char *name;
+ ctf_id_t suid;
+
+ tp = LCTF_INDEX_TO_TYPEPTR(cmp->cm_src, id);
+ name = ctf_strraw(cmp->cm_src, tp->ctt_name);
+ if (CTF_INFO_ISROOT(tp->ctt_info) != 0)
+ flags = CTF_ADD_ROOT;
+ else
+ flags = CTF_ADD_NONROOT;
+ kind = ctf_type_kind(cmp->cm_src, id);
+
+ if (kind == CTF_K_STRUCT)
+ suid = ctf_add_struct(cmp->cm_out, flags, name);
+ else
+ suid = ctf_add_union(cmp->cm_out, flags, name);
+
+ if (suid == CTF_ERR)
+ return (suid);
+
+ /*
+ * If this is a forward reference then it's mapping should already
+ * exist.
+ */
+ if (forward == B_FALSE) {
+ VERIFY(cmp->cm_tmap[id].cmt_map == 0);
+ cmp->cm_tmap[id].cmt_map = suid;
+ ctf_dprintf("added sou \"%s\" as (%d) %d->%d\n", name, kind, id,
+ suid);
+ } else {
+ VERIFY(cmp->cm_tmap[id].cmt_map == suid);
+ }
+ cmp->cm_tmap[id].cmt_fixup = B_TRUE;
+
+ return (0);
+}
+
+static int
+ctf_merge_add_type(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int kind, ret;
+
+ /*
+ * We may end up evaluating a type more than once as we may deal with it
+ * as we recursively evaluate some kind of reference and then we may see
+ * it normally.
+ */
+ if (cmp->cm_tmap[id].cmt_map != 0)
+ return (0);
+
+ kind = ctf_type_kind(cmp->cm_src, id);
+ switch (kind) {
+ case CTF_K_INTEGER:
+ case CTF_K_FLOAT:
+ ret = ctf_merge_add_number(cmp, id);
+ break;
+ case CTF_K_ARRAY:
+ ret = ctf_merge_add_array(cmp, id);
+ break;
+ case CTF_K_POINTER:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ ret = ctf_merge_add_reftype(cmp, id);
+ break;
+ case CTF_K_TYPEDEF:
+ ret = ctf_merge_add_typedef(cmp, id);
+ break;
+ case CTF_K_ENUM:
+ ret = ctf_merge_add_enum(cmp, id);
+ break;
+ case CTF_K_FUNCTION:
+ ret = ctf_merge_add_func(cmp, id);
+ break;
+ case CTF_K_FORWARD:
+ ret = ctf_merge_add_forward(cmp, id);
+ break;
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ ret = ctf_merge_add_sou(cmp, id, B_FALSE);
+ break;
+ case CTF_K_UNKNOWN:
+ /*
+ * We don't add uknown types, and we later assert that nothing
+ * should reference them.
+ */
+ return (0);
+ default:
+ abort();
+ }
+
+ return (ret);
+}
+
+static int
+ctf_merge_fixup_sou(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ ctf_dtdef_t *dtd;
+ ctf_merge_su_t cms;
+ ctf_id_t mapid;
+ ssize_t size;
+
+ mapid = cmp->cm_tmap[id].cmt_map;
+ VERIFY(mapid != 0);
+ dtd = ctf_dtd_lookup(cmp->cm_out, mapid);
+ VERIFY(dtd != NULL);
+
+ ctf_dprintf("Trying to fix up sou %d\n", id);
+ cms.cms_cm = cmp;
+ cms.cms_id = mapid;
+ if (ctf_member_iter(cmp->cm_src, id, ctf_merge_add_member, &cms) != 0)
+ return (CTF_ERR);
+
+ if ((size = ctf_type_size(cmp->cm_src, id)) == CTF_ERR)
+ return (CTF_ERR);
+ if (ctf_set_size(cmp->cm_out, mapid, size) == CTF_ERR)
+ return (CTF_ERR);
+
+ return (0);
+}
+
+static int
+ctf_merge_fixup_type(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ int kind, ret;
+
+ kind = ctf_type_kind(cmp->cm_src, id);
+ switch (kind) {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ ret = ctf_merge_fixup_sou(cmp, id);
+ break;
+ default:
+ VERIFY(0);
+ ret = CTF_ERR;
+ }
+
+ return (ret);
+}
+
+/*
+ * Now that we've successfully merged everything, we're going to clean
+ * up the merge type table. Traditionally if we had just two different
+ * files that we were working between, the types would be fully
+ * resolved. However, because we were comparing with ourself every step
+ * of the way and not our reduced self, we need to go through and update
+ * every mapped entry to what it now points to in the deduped file.
+ */
+static void
+ctf_merge_fixup_dedup_map(ctf_merge_types_t *cmp)
+{
+ int i;
+
+ for (i = 1; i < cmp->cm_src->ctf_typemax + 1; i++) {
+ ctf_id_t tid;
+
+ /*
+ * Missing types always have their id updated to exactly what it
+ * should be.
+ */
+ if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
+ VERIFY(cmp->cm_tmap[i].cmt_map != 0);
+ continue;
+ }
+
+ tid = i;
+ while (cmp->cm_tmap[tid].cmt_missing == B_FALSE) {
+ VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
+ tid = cmp->cm_tmap[tid].cmt_map;
+ }
+ VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
+ cmp->cm_tmap[i].cmt_map = cmp->cm_tmap[tid].cmt_map;
+ }
+}
+
+
+/*
+ * We're going to do three passes over the containers.
+ *
+ * Pass 1 checks for forward references in the output container that we know
+ * exist in the source container.
+ *
+ * Pass 2 adds all the missing types from the source container. As part of this
+ * we may be adding a type as a forward reference that doesn't exist yet.
+ * Any types that we encounter in this form, we need to add to a third pass.
+ *
+ * Pass 3 is the fixup pass. Here we go through and find all the types that were
+ * missing in the first.
+ *
+ * Importantly, we *must* call ctf_update between the second and third pass,
+ * otherwise several of the libctf functions will not properly find the data in
+ * the container. If we're doing a dedup we also fix up the type mapping.
+ */
+static int
+ctf_merge_common(ctf_merge_types_t *cmp)
+{
+ int ret, i;
+
+ ctf_phase_dump(cmp->cm_src, "merge-common-src");
+ ctf_phase_dump(cmp->cm_out, "merge-common-dest");
+
+ /* Pass 1 */
+ for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
+ if (cmp->cm_tmap[i].cmt_forward == B_TRUE) {
+ ret = ctf_merge_add_sou(cmp, i, B_TRUE);
+ if (ret != 0) {
+ return (ret);
+ }
+ }
+ }
+
+ /* Pass 2 */
+ for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
+ if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
+ ret = ctf_merge_add_type(cmp, i);
+ if (ret != 0) {
+ ctf_dprintf("Failed to merge type %d\n", i);
+ return (ret);
+ }
+ }
+ }
+
+ ret = ctf_update(cmp->cm_out);
+ if (ret != 0)
+ return (ret);
+
+ if (cmp->cm_dedup == B_TRUE) {
+ ctf_merge_fixup_dedup_map(cmp);
+ }
+
+ ctf_dprintf("Beginning merge pass 3\n");
+ /* Pass 3 */
+ for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
+ if (cmp->cm_tmap[i].cmt_fixup == B_TRUE) {
+ ret = ctf_merge_fixup_type(cmp, i);
+ if (ret != 0)
+ return (ret);
+ }
+ }
+
+ if (cmp->cm_dedup == B_TRUE) {
+ ctf_merge_fixup_dedup_map(cmp);
+ }
+
+ return (0);
+}
+
+/*
+ * Uniquification is slightly different from a stock merge. For starters, we
+ * don't need to replace any forward references in the output. In this case
+ * though, the types that already exist are in a parent container to the empty
+ * output container.
+ */
+static int
+ctf_merge_uniquify_types(ctf_merge_types_t *cmp)
+{
+ int i, ret;
+
+ for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
+ if (cmp->cm_tmap[i].cmt_missing == B_FALSE)
+ continue;
+ ret = ctf_merge_add_type(cmp, i);
+ if (ret != 0)
+ return (ret);
+ }
+
+ ret = ctf_update(cmp->cm_out);
+ if (ret != 0)
+ return (ret);
+
+ for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
+ if (cmp->cm_tmap[i].cmt_fixup == B_FALSE)
+ continue;
+ ret = ctf_merge_fixup_type(cmp, i);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+ctf_merge_types_init(ctf_merge_types_t *cmp)
+{
+ cmp->cm_tmap = ctf_alloc(sizeof (ctf_merge_tinfo_t) *
+ (cmp->cm_src->ctf_typemax + 1));
+ if (cmp->cm_tmap == NULL)
+ return (ctf_set_errno(cmp->cm_out, ENOMEM));
+ bzero(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
+ (cmp->cm_src->ctf_typemax + 1));
+ return (0);
+}
+
+static void
+ctf_merge_types_fini(ctf_merge_types_t *cmp)
+{
+ ctf_free(cmp->cm_tmap, sizeof (ctf_merge_tinfo_t) *
+ (cmp->cm_src->ctf_typemax + 1));
+}
+
+/*
+ * Merge the types contained inside of two input files. The second input file is
+ * always going to be the destination. We're guaranteed that it's always
+ * writeable.
+ */
+static int
+ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
+{
+ int ret;
+ ctf_merge_types_t cm;
+ ctf_diff_t *cdp;
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+ ctf_merge_input_t *scmi = arg;
+ ctf_merge_input_t *dcmi = arg2;
+ ctf_file_t *out = dcmi->cmi_input;
+ ctf_file_t *source = scmi->cmi_input;
+
+ ctf_dprintf("merging %p->%p\n", source, out);
+
+ if (!(out->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno(out, ECTF_RDONLY));
+
+ if (ctf_getmodel(out) != ctf_getmodel(source))
+ return (ctf_set_errno(out, ECTF_DMODEL));
+
+ if ((ret = ctf_diff_init(out, source, &cdp)) != 0)
+ return (ret);
+
+ cm.cm_out = out;
+ cm.cm_src = source;
+ cm.cm_dedup = B_FALSE;
+ cm.cm_unique = B_FALSE;
+ ret = ctf_merge_types_init(&cm);
+ if (ret != 0) {
+ ctf_diff_fini(cdp);
+ return (ctf_set_errno(out, ret));
+ }
+
+ ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
+ if (ret != 0)
+ goto cleanup;
+ ret = ctf_merge_common(&cm);
+ ctf_dprintf("merge common returned with %d\n", ret);
+ if (ret == 0) {
+ ret = ctf_update(out);
+ ctf_dprintf("update returned with %d\n", ret);
+ } else {
+ goto cleanup;
+ }
+
+ /*
+ * Now we need to fix up the object and function maps.
+ */
+ for (cmo = list_head(&scmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&scmi->cmi_omap, cmo)) {
+ if (cmo->cmo_tid == 0)
+ continue;
+ VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
+ cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&scmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&scmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
+ cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+
+ /*
+ * Now that we've fixed things up, we need to give our function and
+ * object maps to the destination, such that it can continue to update
+ * them going forward.
+ */
+ list_move_tail(&dcmi->cmi_fmap, &scmi->cmi_fmap);
+ list_move_tail(&dcmi->cmi_omap, &scmi->cmi_omap);
+
+cleanup:
+ if (ret == 0)
+ *outp = dcmi;
+ ctf_merge_types_fini(&cm);
+ ctf_diff_fini(cdp);
+ if (ret != 0)
+ return (ctf_errno(out));
+ return (0);
+}
+
+static int
+ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
+{
+ int err, ret;
+ ctf_file_t *out;
+ ctf_merge_types_t cm;
+ ctf_diff_t *cdp;
+ ctf_merge_input_t *cmi;
+ ctf_file_t *parent = cmh->cmh_unique;
+
+ *outp = NULL;
+ out = ctf_fdcreate(cmh->cmh_ofd, &err);
+ if (out == NULL)
+ return (ctf_set_errno(src, err));
+
+ out->ctf_parname = cmh->cmh_pname;
+ if (ctf_setmodel(out, ctf_getmodel(parent)) != 0) {
+ (void) ctf_set_errno(src, ctf_errno(out));
+ ctf_close(out);
+ return (CTF_ERR);
+ }
+
+ if (ctf_import(out, parent) != 0) {
+ (void) ctf_set_errno(src, ctf_errno(out));
+ ctf_close(out);
+ return (CTF_ERR);
+ }
+
+ if ((ret = ctf_diff_init(parent, src, &cdp)) != 0) {
+ ctf_close(out);
+ return (ctf_set_errno(src, ctf_errno(parent)));
+ }
+
+ cm.cm_out = parent;
+ cm.cm_src = src;
+ cm.cm_dedup = B_FALSE;
+ cm.cm_unique = B_TRUE;
+ ret = ctf_merge_types_init(&cm);
+ if (ret != 0) {
+ ctf_close(out);
+ ctf_diff_fini(cdp);
+ return (ctf_set_errno(src, ret));
+ }
+
+ ret = ctf_diff_types(cdp, ctf_merge_diffcb, &cm);
+ if (ret == 0) {
+ cm.cm_out = out;
+ ret = ctf_merge_uniquify_types(&cm);
+ if (ret == 0)
+ ret = ctf_update(out);
+ }
+
+ if (ret != 0) {
+ ctf_merge_types_fini(&cm);
+ ctf_diff_fini(cdp);
+ return (ctf_set_errno(src, ctf_errno(cm.cm_out)));
+ }
+
+ for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
+ cmi = list_next(&cmh->cmh_inputs, cmi)) {
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ if (cmo->cmo_tid == 0)
+ continue;
+ VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
+ cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map !=
+ 0);
+ cmf->cmf_args[i] =
+ cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+ }
+
+ ctf_merge_types_fini(&cm);
+ ctf_diff_fini(cdp);
+ *outp = out;
+ return (0);
+}
+
+static void
+ctf_merge_fini_input(ctf_merge_input_t *cmi)
+{
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+
+ while ((cmo = list_remove_head(&cmi->cmi_omap)) != NULL)
+ ctf_free(cmo, sizeof (ctf_merge_objmap_t));
+
+ while ((cmf = list_remove_head(&cmi->cmi_fmap)) != NULL)
+ ctf_free(cmf, sizeof (ctf_merge_funcmap_t) +
+ sizeof (ctf_id_t) * cmf->cmf_argc);
+
+ if (cmi->cmi_created == B_TRUE && cmi->cmi_input != NULL)
+ ctf_close(cmi->cmi_input);
+
+ ctf_free(cmi, sizeof (ctf_merge_input_t));
+}
+
+void
+ctf_merge_fini(ctf_merge_t *cmh)
+{
+ size_t len;
+ ctf_merge_input_t *cmi;
+
+ if (cmh->cmh_label != NULL) {
+ len = strlen(cmh->cmh_label) + 1;
+ ctf_free(cmh->cmh_label, len);
+ }
+
+ if (cmh->cmh_pname != NULL) {
+ len = strlen(cmh->cmh_pname) + 1;
+ ctf_free(cmh->cmh_pname, len);
+ }
+
+ while ((cmi = list_remove_head(&cmh->cmh_inputs)) != NULL)
+ ctf_merge_fini_input(cmi);
+
+ ctf_free(cmh, sizeof (ctf_merge_t));
+}
+
+ctf_merge_t *
+ctf_merge_init(int fd, int *errp)
+{
+ int err;
+ ctf_merge_t *out;
+ struct stat st;
+
+ if (errp == NULL)
+ errp = &err;
+
+ if (fd != -1 && fstat(fd, &st) != 0) {
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ out = ctf_alloc(sizeof (ctf_merge_t));
+ if (out == NULL) {
+ *errp = ENOMEM;
+ return (NULL);
+ }
+
+ if (fd == -1) {
+ out->cmh_msyms = B_FALSE;
+ } else {
+ out->cmh_msyms = B_TRUE;
+ }
+
+ list_create(&out->cmh_inputs, sizeof (ctf_merge_input_t),
+ offsetof(ctf_merge_input_t, cmi_node));
+ out->cmh_ninputs = 0;
+ out->cmh_nthreads = 1;
+ out->cmh_unique = NULL;
+ out->cmh_ofd = fd;
+ out->cmh_flags = 0;
+ out->cmh_label = NULL;
+ out->cmh_pname = NULL;
+
+ return (out);
+}
+
+int
+ctf_merge_label(ctf_merge_t *cmh, const char *label)
+{
+ char *dup;
+
+ if (label == NULL)
+ return (EINVAL);
+
+ dup = ctf_strdup(label);
+ if (dup == NULL)
+ return (EAGAIN);
+
+ if (cmh->cmh_label != NULL) {
+ size_t len = strlen(cmh->cmh_label) + 1;
+ ctf_free(cmh->cmh_label, len);
+ }
+
+ cmh->cmh_label = dup;
+ return (0);
+}
+
+static int
+ctf_merge_add_funcs(const char *name, ulong_t idx, ctf_funcinfo_t *fip,
+ void *arg)
+{
+ ctf_merge_input_t *cmi = arg;
+ ctf_merge_funcmap_t *fmap;
+
+ fmap = ctf_alloc(sizeof (ctf_merge_funcmap_t) +
+ sizeof (ctf_id_t) * fip->ctc_argc);
+ if (fmap == NULL)
+ return (ENOMEM);
+
+ fmap->cmf_idx = idx;
+ fmap->cmf_rtid = fip->ctc_return;
+ fmap->cmf_flags = fip->ctc_flags;
+ fmap->cmf_argc = fip->ctc_argc;
+ fmap->cmf_name = name;
+
+ if (ctf_func_args(cmi->cmi_input, idx, fmap->cmf_argc,
+ fmap->cmf_args) != 0) {
+ ctf_free(fmap, sizeof (ctf_merge_funcmap_t) +
+ sizeof (ctf_id_t) * fip->ctc_argc);
+ return (ctf_errno(cmi->cmi_input));
+ }
+
+ list_insert_tail(&cmi->cmi_fmap, fmap);
+ return (0);
+}
+
+static int
+ctf_merge_add_objs(const char *name, ctf_id_t id, ulong_t idx, void *arg)
+{
+ ctf_merge_input_t *cmi = arg;
+ ctf_merge_objmap_t *cmo;
+
+ cmo = ctf_alloc(sizeof (ctf_merge_objmap_t));
+ if (cmo == NULL)
+ return (ENOMEM);
+
+ cmo->cmo_name = name;
+ cmo->cmo_idx = idx;
+ cmo->cmo_tid = id;
+ list_insert_tail(&cmi->cmi_omap, cmo);
+ return (0);
+}
+
+/*
+ * Whenever we create an entry to merge, we then go and add a second empty
+ * ctf_file_t which we use for the purposes of our merging. It's not the best,
+ * but it's the best that we've got at the moment.
+ */
+int
+ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
+{
+ int ret;
+ ctf_merge_input_t *cmi;
+ ctf_file_t *empty;
+
+ if (input->ctf_flags & LCTF_CHILD)
+ return (ECTF_MCHILD);
+
+ cmi = ctf_alloc(sizeof (ctf_merge_input_t));
+ if (cmi == NULL)
+ return (ENOMEM);
+
+ cmi->cmi_created = B_FALSE;
+ cmi->cmi_input = input;
+ list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_funcmap_t, cmf_node));
+ list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_objmap_t, cmo_node));
+
+ if (cmh->cmh_msyms == B_TRUE) {
+ if ((ret = ctf_function_iter(input, ctf_merge_add_funcs,
+ cmi)) != 0) {
+ ctf_merge_fini_input(cmi);
+ return (ret);
+ }
+
+ if ((ret = ctf_object_iter(input, ctf_merge_add_objs,
+ cmi)) != 0) {
+ ctf_merge_fini_input(cmi);
+ return (ret);
+ }
+ }
+
+ list_insert_tail(&cmh->cmh_inputs, cmi);
+ cmh->cmh_ninputs++;
+
+ /* And now the empty one to merge into this */
+ cmi = ctf_alloc(sizeof (ctf_merge_input_t));
+ if (cmi == NULL)
+ return (ENOMEM);
+ list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_funcmap_t, cmf_node));
+ list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_objmap_t, cmo_node));
+
+ empty = ctf_fdcreate(cmh->cmh_ofd, &ret);
+ if (empty == NULL)
+ return (ret);
+ cmi->cmi_input = empty;
+ cmi->cmi_created = B_TRUE;
+
+ if (ctf_setmodel(empty, ctf_getmodel(input)) == CTF_ERR) {
+ return (ctf_errno(empty));
+ }
+
+ list_insert_tail(&cmh->cmh_inputs, cmi);
+ cmh->cmh_ninputs++;
+ ctf_dprintf("added containers %p and %p\n", input, empty);
+ return (0);
+}
+
+int
+ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
+{
+ char *dup;
+
+ if (u->ctf_flags & LCTF_CHILD)
+ return (ECTF_MCHILD);
+ if (pname == NULL)
+ return (EINVAL);
+ dup = ctf_strdup(pname);
+ if (dup == NULL)
+ return (EINVAL);
+ if (cmh->cmh_pname != NULL) {
+ size_t len = strlen(cmh->cmh_pname) + 1;
+ ctf_free(cmh->cmh_pname, len);
+ }
+ cmh->cmh_pname = dup;
+ cmh->cmh_unique = u;
+ return (0);
+}
+
+static int
+ctf_merge_symbols(ctf_merge_t *cmh, ctf_file_t *fp)
+{
+ int err;
+ ulong_t i;
+
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ ctf_merge_input_t *cmi;
+ ctf_merge_objmap_t *cmo;
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ int type = ELF32_ST_TYPE(symp->st_info);
+ if (type != STT_OBJECT)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ int type = ELF64_ST_TYPE(symp->st_info);
+ if (type != STT_OBJECT)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ }
+
+ cmo = NULL;
+ for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
+ cmi = list_next(&cmh->cmh_inputs, cmi)) {
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ if (strcmp(cmo->cmo_name, name) == 0)
+ goto found;
+ }
+ }
+found:
+ if (cmo != NULL) {
+ if (cmo->cmo_tid == 0)
+ continue;
+ if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0) {
+ ctf_dprintf("Failed to add symbol %s->%d: %s\n",
+ name, cmo->cmo_tid,
+ ctf_errmsg(ctf_errno(fp)));
+ return (err);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int
+ctf_merge_functions(ctf_merge_t *cmh, ctf_file_t *fp)
+{
+ int err;
+ ulong_t i;
+ ctf_funcinfo_t fi;
+
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ ctf_merge_input_t *cmi;
+ ctf_merge_funcmap_t *cmf;
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ int type = ELF32_ST_TYPE(symp->st_info);
+ if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ int type = ELF64_ST_TYPE(symp->st_info);
+ if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ }
+
+ cmf = NULL;
+ for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
+ cmi = list_next(&cmh->cmh_inputs, cmi)) {
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ if (strcmp(cmf->cmf_name, name) == 0)
+ goto found;
+ }
+ }
+found:
+ if (cmf != NULL) {
+ fi.ctc_return = cmf->cmf_rtid;
+ fi.ctc_argc = cmf->cmf_argc;
+ fi.ctc_flags = cmf->cmf_flags;
+ if ((err = ctf_add_function(fp, i, &fi,
+ cmf->cmf_args)) != 0)
+ return (err);
+ }
+ }
+
+ return (0);
+
+}
+
+int
+ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
+{
+ int err, merr;
+ ctf_merge_input_t *cmi;
+ ctf_id_t ltype;
+ mergeq_t *mqp;
+ ctf_merge_input_t *final;
+ ctf_file_t *out;
+
+ if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
+ const char *label = ctf_label_topmost(cmh->cmh_unique);
+ if (label == NULL)
+ return (ECTF_NOLABEL);
+ if (strcmp(label, cmh->cmh_label) != 0)
+ return (ECTF_LCONFLICT);
+ }
+
+ if (mergeq_init(&mqp, cmh->cmh_nthreads) == -1) {
+ return (errno);
+ }
+
+ /*
+ * We should consider doing a divide and conquer and parallel merge
+ * here. If we did, we'd want to use some number of threads to perform
+ * this operation.
+ */
+ VERIFY(cmh->cmh_ninputs % 2 == 0);
+ for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
+ cmi = list_next(&cmh->cmh_inputs, cmi)) {
+ if (mergeq_add(mqp, cmi) == -1) {
+ err = errno;
+ mergeq_fini(mqp);
+ }
+ }
+
+ err = mergeq_merge(mqp, ctf_merge_types, NULL, (void **)&final, &merr);
+ mergeq_fini(mqp);
+
+ if (err == MERGEQ_ERROR) {
+ return (errno);
+ } else if (err == MERGEQ_UERROR) {
+ return (merr);
+ }
+
+ /*
+ * Disassociate the generated ctf_file_t from the original input. That
+ * way when the input gets cleaned up, we don't accidentally kill the
+ * final reference to the ctf_file_t. If it gets uniquified then we'll
+ * kill it.
+ */
+ VERIFY(final->cmi_input != NULL);
+ out = final->cmi_input;
+ final->cmi_input = NULL;
+
+ ctf_dprintf("preparing to uniquify against: %p\n", cmh->cmh_unique);
+ if (cmh->cmh_unique != NULL) {
+ ctf_file_t *u;
+ err = ctf_uniquify_types(cmh, out, &u);
+ if (err != 0) {
+ err = ctf_errno(out);
+ ctf_close(out);
+ return (err);
+ }
+ ctf_close(out);
+ out = u;
+ }
+
+ ltype = out->ctf_typemax;
+ if ((out->ctf_flags & LCTF_CHILD) && ltype != 0)
+ ltype += 0x8000;
+ ctf_dprintf("trying to add the label\n");
+ if (cmh->cmh_label != NULL &&
+ ctf_add_label(out, cmh->cmh_label, ltype, 0) != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+
+ ctf_dprintf("merging symbols and the like\n");
+ if (cmh->cmh_msyms == B_TRUE) {
+ err = ctf_merge_symbols(cmh, out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+
+ err = ctf_merge_functions(cmh, out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+ }
+
+ err = ctf_update(out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+
+ *outp = out;
+ return (0);
+}
+
+/*
+ * When we get told that something is unique, eg. same is B_FALSE, then that
+ * tells us that we need to add it to the output. If same is B_TRUE, then we'll
+ * want to record it in the mapping table so that we know how to redirect types
+ * to the extant ones.
+ */
+static void
+ctf_dedup_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
+ ctf_id_t oid, void *arg)
+{
+ ctf_merge_types_t *cmp = arg;
+ ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
+
+ if (same == B_TRUE) {
+ /*
+ * The output id here may itself map to something else.
+ * Therefore, we need to basically walk a chain and see what it
+ * points to until it itself points to a base type, eg. -1.
+ * Otherwise we'll dedup to something which no longer exists.
+ */
+ while (cmt[oid].cmt_missing == B_FALSE)
+ oid = cmt[oid].cmt_map;
+ cmt[iid].cmt_map = oid;
+ ctf_dprintf("%d->%d \n", iid, oid);
+ } else {
+ VERIFY(cmt[iid].cmt_map == 0);
+ cmt[iid].cmt_missing = B_TRUE;
+ ctf_dprintf("%d is missing\n", iid);
+ }
+}
+
+/*
+ * Dedup a CTF container.
+ *
+ * DWARF and other encoding formats that we use to create CTF data may create
+ * multiple copies of a given type. However, after doing a conversion, and
+ * before doing a merge, we'd prefer, if possible, to have every input container
+ * to be unique.
+ *
+ * Doing a deduplication is like a normal merge. However, when we diff the types
+ * in the container, rather than doing a normal diff, we instead want to diff
+ * against any already processed types. eg, for a given type i in a container,
+ * we want to diff it from 0 to i - 1.
+ */
+int
+ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
+{
+ int ret;
+ ctf_diff_t *cdp = NULL;
+ ctf_merge_input_t *cmi, *cmc;
+ ctf_file_t *ifp, *ofp;
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+ ctf_merge_types_t cm;
+
+ if (cmp == NULL || outp == NULL)
+ return (EINVAL);
+
+ ctf_dprintf("encountered %d inputs\n", cmp->cmh_ninputs);
+ if (cmp->cmh_ninputs != 2)
+ return (EINVAL);
+
+ ctf_dprintf("passed argument sanity check\n");
+
+ cmi = list_head(&cmp->cmh_inputs);
+ VERIFY(cmi != NULL);
+ cmc = list_next(&cmp->cmh_inputs, cmi);
+ VERIFY(cmc != NULL);
+ ifp = cmi->cmi_input;
+ ofp = cmc->cmi_input;
+ VERIFY(ifp != NULL);
+ VERIFY(ofp != NULL);
+ cm.cm_src = ifp;
+ cm.cm_out = ofp;
+ cm.cm_dedup = B_TRUE;
+ cm.cm_unique = B_FALSE;
+
+ if ((ret = ctf_merge_types_init(&cm)) != 0) {
+ return (ret);
+ }
+
+ if ((ret = ctf_diff_init(ifp, ifp, &cdp)) != 0)
+ goto err;
+
+ ctf_dprintf("Successfully initialized dedup\n");
+ if ((ret = ctf_diff_self(cdp, ctf_dedup_cb, &cm)) != 0)
+ goto err;
+
+ ctf_dprintf("Successfully diffed types\n");
+ ret = ctf_merge_common(&cm);
+ ctf_dprintf("deduping types result: %d\n", ret);
+ if (ret == 0)
+ ret = ctf_update(cm.cm_out);
+ if (ret != 0)
+ goto err;
+
+ ctf_dprintf("Successfully deduped types\n");
+ ctf_phase_dump(cm.cm_out, "dedup-pre-syms");
+
+
+ /*
+ * Now we need to fix up the object and function maps.
+ */
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ if (cmo->cmo_tid == 0)
+ continue;
+ ctf_dprintf("mapped %s %d->%d\n", cmo->cmo_name,
+ cmo->cmo_tid, cm.cm_tmap[cmo->cmo_tid].cmt_map);
+ cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
+ cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+
+ if (cmp->cmh_msyms == B_TRUE) {
+ ret = ctf_merge_symbols(cmp, cm.cm_out);
+ if (ret != 0) {
+ ret = ctf_errno(cm.cm_out);
+ ctf_dprintf("failed to dedup symbols: %s\n",
+ ctf_errmsg(ret));
+ goto err;
+ }
+
+ ret = ctf_merge_functions(cmp, cm.cm_out);
+ if (ret != 0) {
+ ret = ctf_errno(cm.cm_out);
+ ctf_dprintf("failed to dedup functions: %s\n",
+ ctf_errmsg(ret));
+ goto err;
+ }
+ }
+
+ ret = ctf_update(cm.cm_out);
+ if (ret == 0) {
+ cmc->cmi_input = NULL;
+ *outp = cm.cm_out;
+ }
+err:
+ ctf_merge_types_fini(&cm);
+ ctf_diff_fini(cdp);
+ return (ret);
+}
+
+int
+ctf_merge_set_nthreads(ctf_merge_t *cmp, const uint_t nthrs)
+{
+ if (nthrs == 0)
+ return (EINVAL);
+ cmp->cmh_nthreads = nthrs;
+ return (0);
+}
diff --git a/usr/src/lib/libctf/common/ctf_subr.c b/usr/src/lib/libctf/common/ctf_subr.c
index 467b6a8181..26f7e8c4db 100644
--- a/usr/src/lib/libctf/common/ctf_subr.c
+++ b/usr/src/lib/libctf/common/ctf_subr.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <ctf_impl.h>
#include <libctf.h>
#include <sys/mman.h>
@@ -56,6 +54,18 @@ ctf_alloc(size_t size)
return (malloc(size));
}
+void *
+mergeq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+void *
+workq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
/*ARGSUSED*/
void
ctf_free(void *buf, size_t size)
@@ -63,6 +73,20 @@ ctf_free(void *buf, size_t size)
free(buf);
}
+/*ARGSUSED*/
+void
+mergeq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
+/*ARGSUSED*/
+void
+workq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
const char *
ctf_strerror(int err)
{
diff --git a/usr/src/lib/libctf/common/libctf.h b/usr/src/lib/libctf/common/libctf.h
index 3fd69318de..a5c5027048 100644
--- a/usr/src/lib/libctf/common/libctf.h
+++ b/usr/src/lib/libctf/common/libctf.h
@@ -23,6 +23,9 @@
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2015, Joyent, Inc.
+ */
/*
* This header file defines the interfaces available from the CTF debugger
@@ -32,7 +35,7 @@
* the fullness of time after we gain more experience with the interfaces.
*
* In the meantime, be aware that any program linked with libctf in this
- * release of Solaris is almost guaranteed to break in the next release.
+ * release of illumos is almost guaranteed to break in the next release.
*
* In short, do not user this header file or libctf for any purpose.
*/
@@ -40,9 +43,8 @@
#ifndef _LIBCTF_H
#define _LIBCTF_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/ctf_api.h>
+#include <libelf.h>
#ifdef __cplusplus
extern "C" {
@@ -53,6 +55,46 @@ extern "C" {
*/
extern int _libctf_debug;
+typedef enum ctf_diff_flag {
+ CTF_DIFF_F_IGNORE_INTNAMES = 0x01
+} ctf_diff_flag_t;
+
+typedef struct ctf_diff ctf_diff_t;
+typedef void (*ctf_diff_type_f)(ctf_file_t *, ctf_id_t, boolean_t, ctf_file_t *,
+ ctf_id_t, void *);
+typedef void (*ctf_diff_func_f)(ctf_file_t *, ulong_t, boolean_t, ctf_file_t *,
+ ulong_t, void *);
+typedef void (*ctf_diff_obj_f)(ctf_file_t *, ulong_t, ctf_id_t, boolean_t,
+ ctf_file_t *, ulong_t, ctf_id_t, void *);
+
+extern int ctf_diff_init(ctf_file_t *, ctf_file_t *, ctf_diff_t **);
+extern uint_t ctf_diff_getflags(ctf_diff_t *);
+extern int ctf_diff_setflags(ctf_diff_t *, uint_t);
+extern int ctf_diff_types(ctf_diff_t *, ctf_diff_type_f, void *);
+extern int ctf_diff_functions(ctf_diff_t *, ctf_diff_func_f, void *);
+extern int ctf_diff_objects(ctf_diff_t *, ctf_diff_obj_f, void *);
+extern void ctf_diff_fini(ctf_diff_t *);
+
+#define CTF_CONVERT_F_IGNNONC 0x01
+extern ctf_file_t *ctf_elfconvert(int, Elf *, const char *, uint_t, uint_t,
+ int *, char *, size_t);
+extern ctf_file_t *ctf_fdconvert(int, const char *, uint_t, uint_t, int *,
+ char *, size_t);
+
+typedef struct ctf_merge_handle ctf_merge_t;
+extern ctf_merge_t *ctf_merge_init(int, int *);
+extern int ctf_merge_add(ctf_merge_t *, ctf_file_t *);
+extern int ctf_merge_set_nthreads(ctf_merge_t *, const uint_t);
+extern int ctf_merge_label(ctf_merge_t *, const char *);
+extern int ctf_merge_uniquify(ctf_merge_t *, ctf_file_t *, const char *);
+extern int ctf_merge_merge(ctf_merge_t *, ctf_file_t **);
+extern int ctf_merge_dedup(ctf_merge_t *, ctf_file_t **);
+extern void ctf_merge_fini(ctf_merge_t *);
+
+#define CTF_ELFWRITE_F_COMPRESS 0x1
+extern int ctf_elffdwrite(ctf_file_t *, int, int, int);
+extern int ctf_elfwrite(ctf_file_t *, const char *, const char *, int);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h
new file mode 100644
index 0000000000..11193e97d0
--- /dev/null
+++ b/usr/src/lib/libctf/common/libctf_impl.h
@@ -0,0 +1,59 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBCTF_IMPL_H
+#define _LIBCTF_IMPL_H
+
+/*
+ * Portions of libctf implementations that are only suitable for CTF's userland
+ * library, eg. converting and merging related routines.
+ */
+
+#include <libelf.h>
+#include <libctf.h>
+#include <ctf_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum ctf_conv_status {
+ CTF_CONV_SUCCESS = 0,
+ CTF_CONV_ERROR = 1,
+ CTF_CONV_NOTSUP = 2
+} ctf_conv_status_t;
+
+typedef ctf_conv_status_t (*ctf_convert_f)(int, Elf *, uint_t, int *,
+ ctf_file_t **, char *, size_t);
+extern ctf_conv_status_t ctf_dwarf_convert(int, Elf *, uint_t, int *,
+ ctf_file_t **, char *, size_t);
+
+/*
+ * zlib compression routines
+ */
+extern int ctf_compress(ctf_file_t *fp, void **, size_t *, size_t *);
+
+extern int ctf_diff_self(ctf_diff_t *, ctf_diff_type_f, void *);
+
+/*
+ * Internal debugging aids
+ */
+extern void ctf_phase_dump(ctf_file_t *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBCTF_IMPL_H */
diff --git a/usr/src/lib/libctf/common/mapfile-vers b/usr/src/lib/libctf/common/mapfile-vers
index 5573e8db25..cfd2952bbe 100644
--- a/usr/src/lib/libctf/common/mapfile-vers
+++ b/usr/src/lib/libctf/common/mapfile-vers
@@ -23,7 +23,7 @@
#
#
-# Copyright (c) 2013, Joyent, Inc. All rights reserved.
+# Copyright (c) 2015, Joyent, Inc. All rights reserved.
#
#
@@ -53,10 +53,13 @@ SYMBOL_VERSION SUNWprivate_1.2 {
ctf_add_enumerator;
ctf_add_float;
ctf_add_forward;
+ ctf_add_funcptr;
ctf_add_function;
ctf_add_integer;
+ ctf_add_label;
ctf_add_member;
ctf_add_pointer;
+ ctf_add_object;
ctf_add_restrict;
ctf_add_struct;
ctf_add_type;
@@ -64,17 +67,48 @@ SYMBOL_VERSION SUNWprivate_1.2 {
ctf_add_union;
ctf_add_volatile;
ctf_create;
+ ctf_dataptr;
ctf_delete_type;
+ ctf_diff_init;
+ ctf_diff_fini;
+ ctf_diff_functions;
+ ctf_diff_getflags;
+ ctf_diff_objects;
+ ctf_diff_setflags;
+ ctf_diff_types;
ctf_discard;
ctf_dup;
+ ctf_elfconvert;
+ ctf_elffdwrite;
+ ctf_elfwrite;
ctf_enum_value;
+ ctf_fdconvert;
+ ctf_flags;
+ ctf_func_args_by_id;
+ ctf_func_info_by_id;
+ ctf_function_iter;
+ ctf_kind_name;
ctf_label_info;
ctf_label_iter;
ctf_label_topmost;
ctf_member_info;
+ ctf_merge_add;
+ ctf_merge_dedup;
+ ctf_merge_fini;
+ ctf_merge_init;
+ ctf_merge_label;
+ ctf_merge_merge;
+ ctf_merge_set_nthreads;
+ ctf_merge_uniquify;
+ ctf_object_iter;
ctf_parent_file;
+ ctf_parent_label;
ctf_parent_name;
ctf_set_array;
+ ctf_set_root;
+ ctf_set_size;
+ ctf_string_iter;
+ ctf_symbol_name;
ctf_type_align;
ctf_type_cmp;
ctf_type_compat;
diff --git a/usr/src/lib/libcurses/screen/setupterm.c b/usr/src/lib/libcurses/screen/setupterm.c
index c1f4bdeb04..f67e8751b7 100644
--- a/usr/src/lib/libcurses/screen/setupterm.c
+++ b/usr/src/lib/libcurses/screen/setupterm.c
@@ -37,8 +37,6 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*LINTLIBRARY*/
#include <stdio.h>
@@ -48,6 +46,7 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <zone.h>
#include "curses_inc.h"
#define TERMPATH "/usr/share/lib/terminfo/"
@@ -272,9 +271,11 @@ setupterm(char *term, int filenum, int *errret)
}
if (tfd < 0) {
+ const char *zroot = zone_get_nroot();
/* /usr/share/lib/terminfo/?/$TERM */
if (snprintf(fname, sizeof (fname),
- "%s/%c/%s", TERMPATH, *term, term) >= sizeof (fname)) {
+ "%s/%s/%c/%s", zroot == NULL ? "" : zroot, TERMPATH,
+ *term, term) >= sizeof (fname)) {
term_errno = TERMINFO_TOO_LONG;
goto out_err;
}
diff --git a/usr/src/lib/libdhcpagent/common/dhcpagent_util.c b/usr/src/lib/libdhcpagent/common/dhcpagent_util.c
index 1c381fa08f..7a44ae5249 100644
--- a/usr/src/lib/libdhcpagent/common/dhcpagent_util.c
+++ b/usr/src/lib/libdhcpagent/common/dhcpagent_util.c
@@ -36,6 +36,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <zone.h>
#include "dhcpagent_ipc.h"
#include "dhcpagent_util.h"
@@ -125,6 +126,12 @@ dhcp_start_agent(int timeout)
int ctfd;
pid_t childpid;
ctid_t ct;
+ char dhcpcmd[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+
+ /* Prepend the root of the native code in the brand to the command */
+ (void) snprintf(dhcpcmd, sizeof (dhcpcmd), "%s%s", zroot != NULL ?
+ zroot : "", DHCP_AGENT_PATH);
/*
* just send a dummy request to the agent to find out if it's
@@ -160,7 +167,7 @@ dhcp_start_agent(int timeout)
goto fail;
case 0:
- (void) execl(DHCP_AGENT_PATH, DHCP_AGENT_PATH, (char *)0);
+ (void) execl(dhcpcmd, dhcpcmd, (char *)0);
_exit(EXIT_FAILURE);
default:
diff --git a/usr/src/lib/libdladm/Makefile b/usr/src/lib/libdladm/Makefile
index 92de14cc8a..a74b40f58d 100644
--- a/usr/src/lib/libdladm/Makefile
+++ b/usr/src/lib/libdladm/Makefile
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015, Joyent, Inc.
#
#
@@ -29,7 +30,7 @@ HDRS = libdladm.h libdladm_impl.h libdllink.h libdlaggr.h \
libdlwlan.h libdlwlan_impl.h libdlvnic.h libdlvlan.h \
libdlmgmt.h libdlflow.h libdlflow_impl.h libdlstat.h \
libdlether.h libdlsim.h libdlbridge.h libdliptun.h \
- libdlib.h
+ libdlib.h libdloverlay.h
HDRDIR = common
@@ -50,6 +51,14 @@ MSGFILES = common/libdladm.c common/linkprop.c common/secobj.c \
XGETFLAGS = -a -x libdladm.xcl
+TYPECHECK_LIB = libdladm.so.1
+TYPELIST = overlay_ioc_create_t \
+ overlay_ioc_activate_t \
+ overlay_ioc_delete_t \
+ overlay_ioc_nprops_t \
+ overlay_ioc_propinfo_t \
+ overlay_ioc_prop_t
+
all := TARGET = all
clean := TARGET = clean
clobber := TARGET = clobber
@@ -62,7 +71,7 @@ all clean clobber install lint: $(SUBDIRS)
install_h: $(ROOTHDRS)
-check: $(CHECKHDRS)
+check: $(CHECKHDRS) $(TYPECHECK)
$(POFILE): pofile_MSGFILES
diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com
index b6fa5cad2e..f9270f9769 100644
--- a/usr/src/lib/libdladm/Makefile.com
+++ b/usr/src/lib/libdladm/Makefile.com
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015, Joyent, Inc.
#
LIBRARY = libdladm.a
@@ -27,7 +28,8 @@ VERS = .1
OBJECTS = libdladm.o secobj.o linkprop.o libdllink.o libdlaggr.o \
libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o libdlib.o\
flowattr.o flowprop.o propfuncs.o libdlflow.o libdlstat.o \
- usage.o libdlether.o libdlsim.o libdlbridge.o libdliptun.o
+ usage.o libdlether.o libdlsim.o libdlbridge.o libdliptun.o \
+ libdloverlay.o
include ../../Makefile.lib
@@ -36,7 +38,7 @@ include ../../Makefile.rootfs
LIBS = $(DYNLIB) $(LINTLIB)
LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair \
- -lexacct -lnsl -lkstat -lpool
+ -lexacct -lnsl -lkstat -lpool -lvarpd
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
@@ -48,6 +50,9 @@ CERRWARN += -_gcc=-Wno-unused-label
CERRWARN += -_gcc=-Wno-uninitialized
CPPFLAGS += -I$(SRCDIR) -D_REENTRANT
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
.KEEP_STATE:
all: $(LIBS)
diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c
index b8e744f4f9..211a775d89 100644
--- a/usr/src/lib/libdladm/common/libdladm.c
+++ b/usr/src/lib/libdladm/common/libdladm.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc.
*/
#include <unistd.h>
@@ -29,6 +30,9 @@
#include <strings.h>
#include <dirent.h>
#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
@@ -418,6 +422,9 @@ dladm_status2str(dladm_status_t status, char *buf)
case DLADM_STATUS_INVALID_MTU:
s = "MTU check failed, MTU outside of device's supported range";
break;
+ case DLADM_STATUS_BAD_ENCAP:
+ s = "invalid encapsulation protocol";
+ break;
default:
s = "<unknown error>";
break;
@@ -654,6 +661,9 @@ dladm_class2str(datalink_class_t class, char *buf)
case DATALINK_CLASS_PART:
s = "part";
break;
+ case DATALINK_CLASS_OVERLAY:
+ s = "overlay";
+ break;
default:
s = "unknown";
break;
@@ -1139,15 +1149,15 @@ dladm_strs2range(char **prop_val, uint_t val_cnt, mac_propval_type_t type,
* Convert a mac_propval_range_t structure into an array of elements.
*/
dladm_status_t
-dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem)
+dladm_range2list(const mac_propval_range_t *rangep, void *elem, uint_t *nelem)
{
int i, j, k;
dladm_status_t status = DLADM_STATUS_OK;
switch (rangep->mpr_type) {
case MAC_PROPVAL_UINT32: {
- mac_propval_uint32_range_t *ur;
- uint32_t *elem32 = elem;
+ const mac_propval_uint32_range_t *ur;
+ uint32_t *elem32 = elem;
k = 0;
ur = &rangep->mpr_range_uint32[0];
@@ -1175,13 +1185,13 @@ dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem)
* of single elements or ranges.
*/
int
-dladm_range2strs(mac_propval_range_t *rangep, char **prop_val)
+dladm_range2strs(const mac_propval_range_t *rangep, char **prop_val)
{
int i;
switch (rangep->mpr_type) {
case MAC_PROPVAL_UINT32: {
- mac_propval_uint32_range_t *ur;
+ const mac_propval_uint32_range_t *ur;
/* Write ranges and individual elements */
ur = &rangep->mpr_range_uint32[0];
@@ -1198,6 +1208,20 @@ dladm_range2strs(mac_propval_range_t *rangep, char **prop_val)
}
return (0);
}
+ case MAC_PROPVAL_STR: {
+ const mac_propval_str_range_t *str;
+ size_t coff, len;
+
+ coff = 0;
+ str = &rangep->u.mpr_str;
+ for (i = 0; i < rangep->mpr_count; i++) {
+ len = strlen(&str->mpur_data[coff]);
+ (void) strlcpy(prop_val[i], &str->mpur_data[coff],
+ DLADM_PROP_VAL_MAX);
+ coff += len + 1;
+ }
+ return (0);
+ }
default:
break;
}
@@ -1275,3 +1299,54 @@ dladm_list2range(void *elem, uint_t nelem, mac_propval_type_t type,
return (status);
}
+
+void
+dladm_errlist_init(dladm_errlist_t *erl)
+{
+ bzero(erl, sizeof (dladm_errlist_t));
+}
+
+void
+dladm_errlist_reset(dladm_errlist_t *erl)
+{
+ uint_t i;
+
+ for (i = 0; i < erl->el_count; i++)
+ free(erl->el_errs[i]);
+ free(erl->el_errs);
+ dladm_errlist_init(erl);
+}
+
+dladm_status_t
+dladm_errlist_append(dladm_errlist_t *erl, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ char *m = NULL;
+
+ if (erl->el_count == erl->el_alloc) {
+ int alloc;
+ void *addr;
+ if (erl->el_alloc == 0) {
+ assert(erl->el_errs == NULL);
+ alloc = 32;
+ } else {
+ alloc = erl->el_alloc + 32;
+ }
+ addr = realloc(erl->el_errs, sizeof (char *) * alloc);
+ if (addr == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ erl->el_errs = addr;
+ erl->el_alloc = alloc;
+ }
+
+ va_start(ap, fmt);
+ ret = vasprintf(&m, fmt, ap);
+ va_end(ap);
+ if (ret == -1)
+ return (dladm_errno2status(errno));
+ erl->el_errs[erl->el_count] = m;
+ erl->el_count++;
+ return (DLADM_STATUS_OK);
+}
diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h
index c2fceb25ab..e5da4e3b44 100644
--- a/usr/src/lib/libdladm/common/libdladm.h
+++ b/usr/src/lib/libdladm/common/libdladm.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#ifndef _LIBDLADM_H
@@ -41,7 +42,7 @@ extern "C" {
#endif
#define LINKID_STR_WIDTH 10
-#define DLADM_STRSIZE 256
+#define DLADM_STRSIZE 2048
/*
* option flags taken by the libdladm functions
@@ -71,6 +72,10 @@ extern "C" {
* - DLADM_OPT_BOOT:
* Bypass check functions during boot (used by pool property since pools
* can come up after link properties are set)
+ *
+ * - DLADM_OPT_TRANSIENT:
+ * Indicates that the link assigned to a zone is transient and will be
+ * removed when the zone shuts down.
*/
#define DLADM_OPT_ACTIVE 0x00000001
#define DLADM_OPT_PERSIST 0x00000002
@@ -81,6 +86,7 @@ extern "C" {
#define DLADM_OPT_VLAN 0x00000040
#define DLADM_OPT_NOREFRESH 0x00000080
#define DLADM_OPT_BOOT 0x00000100
+#define DLADM_OPT_TRANSIENT 0x00000200
#define DLADM_WALK_TERMINATE 0
#define DLADM_WALK_CONTINUE -1
@@ -173,7 +179,8 @@ typedef enum {
DLADM_STATUS_NO_IB_HW_RESOURCE,
DLADM_STATUS_INVALID_PKEY_TBL_SIZE,
DLADM_STATUS_PORT_NOPROTO,
- DLADM_STATUS_INVALID_MTU
+ DLADM_STATUS_INVALID_MTU,
+ DLADM_STATUS_BAD_ENCAP
} dladm_status_t;
typedef enum {
@@ -221,6 +228,12 @@ typedef struct dladm_arg_list {
char *al_buf;
} dladm_arg_list_t;
+typedef struct dladm_errlist {
+ uint_t el_count;
+ uint_t el_alloc;
+ char **el_errs;
+} dladm_errlist_t;
+
typedef enum {
DLADM_LOGTYPE_LINK = 1,
DLADM_LOGTYPE_FLOW
@@ -282,12 +295,15 @@ extern dladm_status_t dladm_zone_halt(dladm_handle_t, zoneid_t);
extern dladm_status_t dladm_strs2range(char **, uint_t, mac_propval_type_t,
mac_propval_range_t **);
-extern dladm_status_t dladm_range2list(mac_propval_range_t *, void*,
+extern dladm_status_t dladm_range2list(const mac_propval_range_t *, void *,
uint_t *);
-extern int dladm_range2strs(mac_propval_range_t *, char **);
+extern int dladm_range2strs(const mac_propval_range_t *, char **);
extern dladm_status_t dladm_list2range(void *, uint_t, mac_propval_type_t,
mac_propval_range_t **);
+extern void dladm_errlist_init(dladm_errlist_t *);
+extern void dladm_errlist_reset(dladm_errlist_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h
index 13169285e3..e1a3177808 100644
--- a/usr/src/lib/libdladm/common/libdladm_impl.h
+++ b/usr/src/lib/libdladm/common/libdladm_impl.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#ifndef _LIBDLADM_IMPL_H
@@ -168,6 +169,12 @@ typedef struct resource_prop_s {
*/
#define FBRIDGE "bridge" /* string */
+/*
+ * For error lists
+ */
+extern dladm_status_t dladm_errlist_append(dladm_errlist_t *,
+ const char *, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdladm/common/libdllink.c b/usr/src/lib/libdladm/common/libdllink.c
index 58bec0ad30..7e952b97e9 100644
--- a/usr/src/lib/libdladm/common/libdllink.c
+++ b/usr/src/lib/libdladm/common/libdllink.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -386,10 +387,14 @@ dladm_linkduplex2str(link_duplex_t duplex, char *buf)
/*
* Case 1: rename an existing link1 to a link2 that does not exist.
* Result: <linkid1, link2>
+ * The zonename parameter is used to allow us to create a VNIC in the global
+ * zone which is assigned to a non-global zone. Since there is a race condition
+ * in the create process if two VNICs have the same name, we need to rename it
+ * after it has been assigned to the zone.
*/
static dladm_status_t
i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
- const char *link1, const char *link2, uint32_t flags)
+ const char *link1, const char *link2, uint32_t flags, const char *zonename)
{
dld_ioc_rename_t dir;
dladm_status_t status = DLADM_STATUS_OK;
@@ -402,6 +407,10 @@ i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
dir.dir_linkid1 = linkid1;
dir.dir_linkid2 = DATALINK_INVALID_LINKID;
(void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
+ if (zonename != NULL)
+ dir.dir_zoneinit = B_TRUE;
+ else
+ dir.dir_zoneinit = B_FALSE;
if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
status = dladm_errno2status(errno);
@@ -412,6 +421,7 @@ i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
status = dladm_remap_datalink_id(handle, linkid1, link2);
if (status != DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
(void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
+ dir.dir_zoneinit = B_FALSE;
(void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
}
return (status);
@@ -508,6 +518,7 @@ i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1,
*/
dir.dir_linkid1 = linkid1;
dir.dir_linkid2 = linkid2;
+ dir.dir_zoneinit = B_FALSE;
if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
status = dladm_errno2status(errno);
@@ -616,7 +627,8 @@ done:
}
dladm_status_t
-dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
+dladm_rename_link(dladm_handle_t handle, const char *zonename,
+ const char *link1, const char *link2)
{
datalink_id_t linkid1 = DATALINK_INVALID_LINKID;
datalink_id_t linkid2 = DATALINK_INVALID_LINKID;
@@ -626,11 +638,11 @@ dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
boolean_t remphy2 = B_FALSE;
dladm_status_t status;
- (void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
- &media1);
- if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
- &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
- (flags2 == DLADM_OPT_PERSIST)) {
+ (void) dladm_zname2info(handle, zonename, link1, &linkid1, &flags1,
+ &class1, &media1);
+ if ((dladm_zname2info(handle, zonename, link2, &linkid2, &flags2,
+ &class2, &media2) == DLADM_STATUS_OK) &&
+ (class2 == DATALINK_CLASS_PHYS) && (flags2 == DLADM_OPT_PERSIST)) {
/*
* see whether link2 is a removed physical link.
*/
@@ -644,7 +656,7 @@ dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
* does not exist.
*/
status = i_dladm_rename_link_c1(handle, linkid1, link1,
- link2, flags1);
+ link2, flags1, zonename);
} else if (remphy2) {
/*
* case 2: rename an available link to a REMOVED
diff --git a/usr/src/lib/libdladm/common/libdllink.h b/usr/src/lib/libdladm/common/libdllink.h
index a2830b5e37..a858e78aa3 100644
--- a/usr/src/lib/libdladm/common/libdllink.h
+++ b/usr/src/lib/libdladm/common/libdllink.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent Inc. All rights reserved.
*/
#ifndef _LIBDLLINK_H
@@ -121,7 +122,7 @@ extern dladm_status_t dladm_info(dladm_handle_t, datalink_id_t,
dladm_attr_t *);
extern dladm_status_t dladm_rename_link(dladm_handle_t, const char *,
- const char *);
+ const char *, const char *);
extern dladm_status_t dladm_set_linkprop(dladm_handle_t, datalink_id_t,
const char *, char **, uint_t, uint_t);
@@ -170,6 +171,9 @@ extern dladm_status_t dladm_up_datalink_id(dladm_handle_t, datalink_id_t);
extern dladm_status_t dladm_name2info(dladm_handle_t, const char *,
datalink_id_t *, uint32_t *, datalink_class_t *,
uint32_t *);
+extern dladm_status_t dladm_zname2info(dladm_handle_t, const char *,
+ const char *, datalink_id_t *, uint32_t *,
+ datalink_class_t *, uint32_t *);
extern dladm_status_t dladm_datalink_id2info(dladm_handle_t, datalink_id_t,
uint32_t *, datalink_class_t *, uint32_t *, char *,
size_t);
diff --git a/usr/src/lib/libdladm/common/libdlmgmt.c b/usr/src/lib/libdladm/common/libdlmgmt.c
index 4b0753417c..b5d7aadb4f 100644
--- a/usr/src/lib/libdladm/common/libdlmgmt.c
+++ b/usr/src/lib/libdladm/common/libdlmgmt.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
*/
#include <door.h>
@@ -124,6 +125,7 @@ dladm_create_datalink_id(dladm_handle_t handle, const char *link,
dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
+ dlmgmt_flags |= (flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0;
(void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
createid.ld_class = class;
@@ -285,6 +287,7 @@ dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
+ dlmgmt_flags |= ((flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0);
getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
getnext.ld_class = class;
@@ -528,12 +531,24 @@ dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf,
}
/*
- * Get the link ID that is associated with the given name.
+ * Get the link ID that is associated with the given name in the current zone.
*/
dladm_status_t
dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
{
+ return (dladm_zname2info(handle, NULL, link, linkidp, flagp, classp,
+ mediap));
+}
+
+/*
+ * Get the link ID that is associated with the given zone/name pair.
+ */
+dladm_status_t
+dladm_zname2info(dladm_handle_t handle, const char *zonename, const char *link,
+ datalink_id_t *linkidp, uint32_t *flagp, datalink_class_t *classp,
+ uint32_t *mediap)
+{
dlmgmt_door_getlinkid_t getlinkid;
dlmgmt_getlinkid_retval_t retval;
datalink_id_t linkid;
@@ -542,6 +557,10 @@ dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
+ if (zonename != NULL)
+ getlinkid.ld_zoneid = getzoneidbyname(zonename);
+ else
+ getlinkid.ld_zoneid = -1;
if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
&retval, &sz)) != DLADM_STATUS_OK) {
@@ -621,10 +640,12 @@ dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
if (mediap != NULL)
*mediap = retval.lr_media;
if (flagp != NULL) {
- *flagp = retval.lr_flags & DLMGMT_ACTIVE ?
+ *flagp = (retval.lr_flags & DLMGMT_ACTIVE) ?
DLADM_OPT_ACTIVE : 0;
*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
DLADM_OPT_PERSIST : 0;
+ *flagp |= (retval.lr_flags & DLMGMT_TRANSIENT) ?
+ DLADM_OPT_TRANSIENT : 0;
}
return (DLADM_STATUS_OK);
}
diff --git a/usr/src/lib/libdladm/common/libdloverlay.c b/usr/src/lib/libdladm/common/libdloverlay.c
new file mode 100644
index 0000000000..a83105b91c
--- /dev/null
+++ b/usr/src/lib/libdladm/common/libdloverlay.c
@@ -0,0 +1,908 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#include <libdladm_impl.h>
+#include <libdllink.h>
+#include <libdloverlay.h>
+#include <sys/dld.h>
+#include <sys/overlay.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <libvarpd_client.h>
+
+#define VARPD_PROPERTY_NAME "varpd/id"
+
+static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door";
+
+typedef struct dladm_overlay_propinfo {
+ boolean_t dop_isvarpd;
+ union {
+ overlay_ioc_propinfo_t *dop_overlay;
+ varpd_client_prop_handle_t *dop_varpd;
+ } dop_un;
+} dladm_overlay_propinfo_t;
+
+dladm_status_t
+dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl,
+ const char **namep, uint_t *typep, uint_t *protp, const void **defp,
+ uint32_t *sizep, const mac_propval_range_t **possp)
+{
+ dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl;
+ overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay;
+
+ if (infop->dop_isvarpd == B_FALSE) {
+ if (namep != NULL)
+ *namep = oinfop->oipi_name;
+ if (typep != NULL)
+ *typep = oinfop->oipi_type;
+ if (protp != NULL)
+ *protp = oinfop->oipi_prot;
+ if (defp != NULL)
+ *defp = oinfop->oipi_default;
+ if (sizep != NULL)
+ *sizep = oinfop->oipi_defsize;
+ if (possp != NULL) {
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ *possp = (const mac_propval_range_t *)oinfop->oipi_poss;
+ }
+
+ } else {
+ int ret;
+ ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep,
+ typep, protp, defp, sizep, possp);
+ if (ret != 0)
+ return (dladm_errno2status(ret));
+
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep,
+ const char *val)
+{
+ int ret;
+ int64_t ival;
+ uint64_t uval;
+ char *eptr;
+ struct in6_addr ipv6;
+ struct in_addr ip;
+
+ switch (type) {
+ case OVERLAY_PROP_T_INT:
+ errno = 0;
+ ival = strtol(val, &eptr, 10);
+ if ((ival == 0 && errno == EINVAL) ||
+ ((ival == LONG_MAX || ival == LONG_MIN) &&
+ errno == ERANGE))
+ return (DLADM_STATUS_BADARG);
+ bcopy(&ival, buf, sizeof (int64_t));
+ *sizep = sizeof (int64_t);
+ break;
+ case OVERLAY_PROP_T_UINT:
+ errno = 0;
+ uval = strtol(val, &eptr, 10);
+ if ((uval == 0 && errno == EINVAL) ||
+ (uval == ULONG_MAX && errno == ERANGE))
+ return (DLADM_STATUS_BADARG);
+ bcopy(&uval, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ break;
+ case OVERLAY_PROP_T_STRING:
+ ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX);
+ if (ret >= OVERLAY_PROP_SIZEMAX)
+ return (DLADM_STATUS_BADARG);
+ *sizep = ret + 1;
+ break;
+ case OVERLAY_PROP_T_IP:
+ /*
+ * Always try to parse the IP as an IPv6 address. If that fails,
+ * try to interpret it as an IPv4 address and transform it into
+ * an IPv6 mapped IPv4 address.
+ */
+ if (inet_pton(AF_INET6, val, &ipv6) != 1) {
+ if (inet_pton(AF_INET, val, &ip) != 1)
+ return (DLADM_STATUS_BADARG);
+
+ IN6_INADDR_TO_V4MAPPED(&ip, &ipv6);
+ }
+ bcopy(&ipv6, buf, sizeof (struct in6_addr));
+ *sizep = sizeof (struct in6_addr);
+ break;
+ default:
+ abort();
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl,
+ uint64_t inst, const char *name, char *const *valp, uint_t cnt)
+{
+ int ret;
+ uint32_t size;
+ uint8_t buf[LIBVARPD_PROP_SIZEMAX];
+ varpd_client_prop_handle_t *phdl;
+ uint_t type;
+ dladm_status_t status;
+
+ if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL,
+ NULL)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) !=
+ DLADM_STATUS_OK) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (status);
+ }
+
+ ret = libvarpd_c_prop_set(phdl, buf, size);
+ libvarpd_c_prop_handle_free(phdl);
+
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid,
+ const char *name, char *const *valp, uint_t cnt)
+{
+ int ret;
+ dladm_status_t status;
+ overlay_ioc_propinfo_t info;
+ overlay_ioc_prop_t prop;
+
+ if (linkid == DATALINK_INVALID_LINKID ||
+ name == NULL || valp == NULL || cnt != 1)
+ return (DLADM_STATUS_BADARG);
+
+ bzero(&info, sizeof (overlay_ioc_propinfo_t));
+ info.oipi_linkid = linkid;
+ info.oipi_id = -1;
+ if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >=
+ OVERLAY_PROP_NAMELEN)
+ return (DLADM_STATUS_BADARG);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ prop.oip_linkid = linkid;
+ prop.oip_id = info.oipi_id;
+ prop.oip_name[0] = '\0';
+ if ((ret = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value,
+ &prop.oip_size, valp[0])) != DLADM_STATUS_OK)
+ return (ret);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+
+ return (ret);
+}
+
+/*
+ * Tell the user about any unset required properties.
+ */
+static int
+dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t phdl, void *arg)
+{
+ dladm_status_t status;
+ uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
+ uint_t prot;
+ size_t size = sizeof (buf);
+ const char *name;
+ dladm_errlist_t *errs = arg;
+
+ if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK)
+ return (status);
+
+ if ((prot & OVERLAY_PROP_PERM_REQ) == 0)
+ return (DLADM_WALK_CONTINUE);
+
+ if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) !=
+ DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ if (size == 0)
+ (void) dladm_errlist_append(errs, "unset required property: %s",
+ name);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+/*
+ * We need to clean up the world here. The problem is that we may or may not
+ * actually have everything created. While in the normal case, we'd always have
+ * an overlay device, assigned datalink id, and a varpd instance, we might not
+ * have any of those, except for the datalink instance. Therefore, as long as
+ * the id refers to a valid overlay, we should try to clean up as much of the
+ * state as possible and most importantly, we need to make sure we delete the
+ * datalink id. If we fail to do that, then that name will become lost to time.
+ */
+dladm_status_t
+dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid)
+{
+ datalink_class_t class;
+ overlay_ioc_delete_t oid;
+ varpd_client_handle_t *chdl;
+ int ret;
+ uint32_t flags;
+ uint64_t varpdid;
+
+ if (dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
+ NULL, 0) != DLADM_STATUS_OK)
+ return (DLADM_STATUS_BADARG);
+
+ if (class != DATALINK_CLASS_OVERLAY)
+ return (DLADM_STATUS_BADARG);
+
+ oid.oid_linkid = linkid;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid);
+ if (ret != 0 && errno != ENOENT) {
+ return (dladm_errno2status(errno));
+ }
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) {
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ if (ret == ENOENT) {
+ goto finish;
+ }
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_destroy(chdl, varpdid);
+finish:
+ (void) libvarpd_c_destroy(chdl);
+ (void) dladm_destroy_datalink_id(handle, linkid, flags);
+
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep)
+{
+ int ret;
+ overlay_ioc_prop_t oip;
+ dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl;
+
+ /*
+ * It'd be nice if we had a better or more specific error for this. If
+ * this kind of error becomes common place, let's get a better dladm
+ * error.
+ */
+ if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX)
+ return (dladm_errno2status(ERANGE));
+
+ if (infop->dop_isvarpd == B_FALSE) {
+ bzero(&oip, sizeof (overlay_ioc_prop_t));
+ oip.oip_linkid = linkid;
+ oip.oip_id = infop->dop_un.dop_overlay->oipi_id;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip);
+ if (ret != 0)
+ return (dladm_errno2status(errno));
+ bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX);
+ *sizep = oip.oip_size;
+ } else {
+ uint32_t size = *sizep;
+
+ ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size);
+ if (ret != 0)
+ return (dladm_errno2status(errno));
+ *sizep = size;
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid,
+ uint64_t varpdid, dladm_overlay_prop_f func, void *arg)
+{
+ int ret, i;
+ varpd_client_handle_t *chdl;
+ varpd_client_prop_handle_t *phdl;
+ uint_t nprops;
+ dladm_status_t status;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) {
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ status = DLADM_STATUS_OK;
+ for (i = 0; i < nprops; i++) {
+ dladm_overlay_propinfo_t dop;
+
+ bzero(&dop, sizeof (dop));
+ dop.dop_isvarpd = B_TRUE;
+ dop.dop_un.dop_varpd = phdl;
+
+ if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) {
+ status = dladm_errno2status(ret);
+ break;
+ }
+
+ ret = func(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, arg);
+ if (ret == DLADM_WALK_TERMINATE)
+ break;
+ }
+
+ libvarpd_c_prop_handle_free(phdl);
+ libvarpd_c_destroy(chdl);
+
+ return (status);
+}
+
+dladm_status_t
+dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs)
+{
+ int i, ret;
+ char buf[MAXLINKNAMELEN];
+ char errmsg[DLADM_STRSIZE];
+ datalink_class_t class;
+ dladm_status_t info_status;
+ overlay_ioc_nprops_t oin;
+ overlay_ioc_propinfo_t oipi;
+ dladm_overlay_propinfo_t dop;
+ uint64_t varpdid = UINT64_MAX;
+
+ if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class,
+ NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
+ (void) dladm_errlist_append(errs, "failed to get info for "
+ "datalink id %u: %s",
+ linkid, dladm_status2str(info_status, errmsg));
+ return (DLADM_STATUS_BADARG);
+ }
+
+ if (class != DATALINK_CLASS_OVERLAY) {
+ (void) dladm_errlist_append(errs, "%s is not an overlay", buf);
+ return (DLADM_STATUS_BADARG);
+ }
+
+ bzero(&oin, sizeof (overlay_ioc_nprops_t));
+ oin.oipn_linkid = linkid;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin);
+ if (ret != 0) {
+ (void) dladm_errlist_append(errs, "failed to get "
+ "overlay properties for overlay %s: %s",
+ buf, strerror(errno));
+ return (dladm_errno2status(errno));
+ }
+
+ for (i = 0; i < oin.oipn_nprops; i++) {
+ bzero(&dop, sizeof (dladm_overlay_propinfo_t));
+ bzero(&oipi, sizeof (overlay_ioc_propinfo_t));
+ oipi.oipi_linkid = linkid;
+ oipi.oipi_id = i;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi);
+ if (ret != 0) {
+ (void) dladm_errlist_append(errs, "failed to get "
+ "propinfo for overlay %s, property %d: %s",
+ buf, i, strerror(errno));
+ return (dladm_errno2status(errno));
+ }
+
+ dop.dop_isvarpd = B_FALSE;
+ dop.dop_un.dop_overlay = &oipi;
+ ret = func(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, arg);
+ if (ret == DLADM_WALK_TERMINATE)
+ break;
+
+ if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) {
+ uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
+ size_t bufsize = sizeof (buf);
+ uint64_t *vp;
+
+ if (dladm_overlay_get_prop(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, buf,
+ &bufsize) != DLADM_STATUS_OK)
+ continue;
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ vp = (uint64_t *)buf;
+ varpdid = *vp;
+ }
+ }
+
+ /* Should this really be possible? */
+ if (varpdid == UINT64_MAX)
+ return (DLADM_STATUS_OK);
+
+ ret = dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func,
+ arg);
+ if (ret != DLADM_STATUS_OK) {
+ (void) dladm_errlist_append(errs,
+ "failed to get varpd props for "
+ "overlay %s, varpd id %llu: %s",
+ buf, varpdid, dladm_status2str(info_status, errmsg));
+ }
+ return (ret);
+}
+
+dladm_status_t
+dladm_overlay_create(dladm_handle_t handle, const char *name,
+ const char *encap, const char *search, uint64_t vid,
+ dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags)
+{
+ int ret, i;
+ dladm_status_t status;
+ datalink_id_t linkid;
+ overlay_ioc_create_t oic;
+ overlay_ioc_activate_t oia;
+ size_t slen;
+ varpd_client_handle_t *vch;
+ uint64_t id;
+
+ status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY,
+ DL_ETHER, flags, &linkid);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ bzero(&oic, sizeof (oic));
+ oic.oic_linkid = linkid;
+ oic.oic_vnetid = vid;
+ (void) strlcpy(oic.oic_encap, encap, MAXLINKNAMELEN);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic);
+ if (ret != 0) {
+ /*
+ * It'd be nice if we had private errors so we could better
+ * distinguish between different classes of errors.
+ */
+ status = dladm_errno2status(errno);
+ }
+
+ if (status != DLADM_STATUS_OK) {
+ (void) dladm_destroy_datalink_id(handle, linkid, flags);
+ return (status);
+ }
+
+ slen = strlen(search);
+ for (i = 0; props != NULL && i < props->al_count; i++) {
+ dladm_arg_info_t *aip = &props->al_info[i];
+
+ /*
+ * If it's a property for the search plugin, eg. it has the
+ * prefix '<search>/', then we don't set the property on the
+ * overlay device and instead set it on the varpd instance.
+ */
+ if (strncmp(aip->ai_name, search, slen) == 0 &&
+ aip->ai_name[slen] == '/')
+ continue;
+ status = dladm_overlay_setprop(handle, linkid, aip->ai_name,
+ aip->ai_val, aip->ai_count);
+ if (status != DLADM_STATUS_OK) {
+ (void) dladm_errlist_append(errs,
+ "failed to set property %s",
+ aip->ai_name);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (status);
+ }
+ }
+
+ if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to create libvarpd handle: %s", strerror(ret));
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_create(vch, linkid, search,
+ &id)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to create varpd instance: %s", strerror(ret));
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+
+ for (i = 0; props != NULL && i < props->al_count; i++) {
+ dladm_arg_info_t *aip = &props->al_info[i];
+
+ /*
+ * Skip arguments we've processed already.
+ */
+ if (strncmp(aip->ai_name, search, slen) != 0)
+ continue;
+
+ if (aip->ai_name[slen] != '/')
+ continue;
+
+ ret = dladm_overlay_varpd_setprop(handle, vch, id, aip->ai_name,
+ aip->ai_val, aip->ai_count);
+ if (ret != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to set varpd prop: %s\n",
+ aip->ai_name);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+ }
+
+ if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to activate varpd instance: %s", strerror(ret));
+ (void) dladm_overlay_walk_varpd_prop(handle, linkid, id,
+ dladm_overlay_activate_cb, errs);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+
+ }
+
+ bzero(&oia, sizeof (oia));
+ oia.oia_linkid = linkid;
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia);
+ if (ret != 0) {
+ ret = errno;
+ (void) dladm_errlist_append(errs, "failed to activate "
+ "device: %s", strerror(ret));
+ (void) libvarpd_c_instance_destroy(vch, id);
+ (void) dladm_overlay_walk_prop(handle, linkid,
+ dladm_overlay_activate_cb, errs, errs);
+ status = dladm_errno2status(ret);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ }
+
+ libvarpd_c_destroy(vch);
+ if (status != DLADM_STATUS_OK)
+ (void) dladm_overlay_delete(handle, linkid);
+
+ return (status);
+}
+
+
+
+typedef struct overlay_walk_cb {
+ dladm_handle_t owc_handle;
+ datalink_id_t owc_linkid;
+ void *owc_arg;
+ dladm_overlay_cache_f owc_func;
+ uint_t owc_mode;
+ uint_t owc_dest;
+} overlay_walk_cb_t;
+
+/* ARGSUSED */
+static int
+dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid,
+ const struct ether_addr *key, const varpd_client_cache_entry_t *entry,
+ void *arg)
+{
+ overlay_walk_cb_t *owc = arg;
+ dladm_overlay_point_t point;
+
+ bzero(&point, sizeof (dladm_overlay_point_t));
+ point.dop_dest = owc->owc_dest;
+ point.dop_mac = entry->vcp_mac;
+ point.dop_flags = entry->vcp_flags;
+ point.dop_ip = entry->vcp_ip;
+ point.dop_port = entry->vcp_port;
+
+ if (owc->owc_mode == OVERLAY_TARGET_POINT)
+ point.dop_flags |= DLADM_OVERLAY_F_DEFAULT;
+
+ if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point,
+ owc->owc_arg) == DLADM_WALK_TERMINATE)
+ return (1);
+ return (0);
+}
+
+dladm_status_t
+dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_cache_f func, void *arg)
+{
+ int ret;
+ uint_t mode, dest;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+ overlay_walk_cb_t cbarg;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, &mode)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ cbarg.owc_handle = handle;
+ cbarg.owc_linkid = linkid;
+ cbarg.owc_arg = arg;
+ cbarg.owc_func = func;
+ cbarg.owc_dest = dest;
+ cbarg.owc_mode = mode;
+ ret = libvarpd_c_instance_cache_walk(chdl, varpdid,
+ dladm_overlay_walk_cache_cb, &cbarg);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid)
+{
+ int ret;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_flush(chdl, varpdid);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key)
+{
+ int ret;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, char *val)
+{
+ int ret;
+ uint_t dest;
+ uint64_t varpdid;
+ char *ip, *port = NULL;
+ varpd_client_handle_t *chdl;
+ varpd_client_cache_entry_t vcp;
+
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, NULL)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ /*
+ * Mode tells us what we should expect in val. It we have more than one
+ * thing listed, the canonical format of it right now is mac,ip:port.
+ */
+ bzero(&vcp, sizeof (varpd_client_cache_entry_t));
+
+ if (strcasecmp(val, "drop") == 0) {
+ vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP;
+ goto send;
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if (ether_aton_r(val, &vcp.vcp_mac) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_IP) {
+ if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if ((ip = strchr(val, ',')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ ip++;
+ } else {
+ ip = val;
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_PORT) {
+ if ((port = strchr(val, ':')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ *port = '\0';
+ port++;
+ }
+
+ /* Try v6, then fall back to v4 */
+ ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip);
+ if (ret == -1)
+ abort();
+ if (ret == 0) {
+ struct in_addr v4;
+
+ ret = inet_pton(AF_INET, ip, &v4);
+ if (ret == -1)
+ abort();
+ if (ret == 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip);
+ }
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_PORT) {
+ char *eptr;
+ unsigned long l;
+ if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) {
+ if ((port = strchr(val, ',')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ } else if (port == NULL)
+ port = val;
+
+ errno = 0;
+ l = strtoul(port, &eptr, 10);
+ if (errno != 0 || *eptr != '\0') {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ if (l == 0 || l > UINT16_MAX) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ vcp.vcp_port = l;
+ }
+
+send:
+ ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp);
+
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, dladm_overlay_point_t *point)
+{
+ int ret;
+ uint_t dest, mode;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+ varpd_client_cache_entry_t entry;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, &mode)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry);
+ if (ret == 0) {
+ point->dop_dest = dest;
+ point->dop_mac = entry.vcp_mac;
+ point->dop_flags = entry.vcp_flags;
+ point->dop_ip = entry.vcp_ip;
+ point->dop_port = entry.vcp_port;
+ if (mode == OVERLAY_TARGET_POINT)
+ point->dop_flags |= DLADM_OVERLAY_F_DEFAULT;
+ }
+
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_status_f func, void *arg)
+{
+ int ret;
+ dladm_status_t status;
+ overlay_ioc_status_t ois;
+ dladm_overlay_status_t dos;
+
+ ois.ois_linkid = linkid;
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE :
+ B_FALSE;
+ (void) strlcpy(dos.dos_fmamsg, ois.ois_message,
+ sizeof (dos.dos_fmamsg));
+ func(handle, linkid, &dos, arg);
+ return (DLADM_STATUS_OK);
+}
diff --git a/usr/src/lib/libdladm/common/libdloverlay.h b/usr/src/lib/libdladm/common/libdloverlay.h
new file mode 100644
index 0000000000..39b01ccae3
--- /dev/null
+++ b/usr/src/lib/libdladm/common/libdloverlay.h
@@ -0,0 +1,107 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBDLOVERLAY_H
+#define _LIBDLOVERLAY_H
+
+/*
+ * libdladm Overlay device routines
+ */
+
+#include <libdladm.h>
+#include <libdladm_impl.h>
+#include <sys/overlay.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DLADM_OVERLAY_F_DROP 0x0001
+#define DLADM_OVERLAY_F_DEFAULT 0xf000
+
+typedef struct dladm_overlay_point {
+ uint_t dop_dest;
+ struct ether_addr dop_mac;
+ uint16_t dop_flags;
+ struct in6_addr dop_ip;
+ uint16_t dop_port;
+} dladm_overlay_point_t;
+
+typedef struct dladm_overlay_status {
+ boolean_t dos_degraded;
+ char dos_fmamsg[256];
+} dladm_overlay_status_t;
+
+extern dladm_status_t dladm_overlay_create(dladm_handle_t, const char *,
+ const char *, const char *, uint64_t, dladm_arg_list_t *, dladm_errlist_t *,
+ uint32_t);
+extern dladm_status_t dladm_overlay_delete(dladm_handle_t, datalink_id_t);
+
+typedef void (*dladm_overlay_status_f)(dladm_handle_t, datalink_id_t,
+ dladm_overlay_status_t *, void *);
+extern dladm_status_t dladm_overlay_status(dladm_handle_t, datalink_id_t,
+ dladm_overlay_status_f, void *);
+
+extern dladm_status_t dladm_overlay_cache_flush(dladm_handle_t, datalink_id_t);
+extern dladm_status_t dladm_overlay_cache_delete(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *);
+extern dladm_status_t dladm_overlay_cache_set(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, char *);
+extern dladm_status_t dladm_overlay_cache_get(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, dladm_overlay_point_t *);
+
+#define DLADM_OVERLAY_PROP_SIZEMAX 256
+#define DLADM_OVERLAY_PROP_NAMELEN 32
+
+typedef struct __dladm_overlay_propinfo *dladm_overlay_propinfo_handle_t;
+
+extern dladm_status_t dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t,
+ const char **, uint_t *, uint_t *, const void **, uint32_t *,
+ const mac_propval_range_t **);
+extern dladm_status_t dladm_overlay_get_prop(dladm_handle_t, datalink_id_t,
+ dladm_overlay_propinfo_handle_t, void *buf, size_t *bufsize);
+
+typedef int (*dladm_overlay_prop_f)(dladm_handle_t, datalink_id_t,
+ dladm_overlay_propinfo_handle_t, void *);
+extern dladm_status_t dladm_overlay_walk_prop(dladm_handle_t, datalink_id_t,
+ dladm_overlay_prop_f, void *arg, dladm_errlist_t *);
+
+typedef int (*dladm_overlay_cache_f)(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, const dladm_overlay_point_t *, void *);
+extern dladm_status_t dladm_overlay_walk_cache(dladm_handle_t, datalink_id_t,
+ dladm_overlay_cache_f, void *);
+
+/*
+ * Some day we'll want to support being able to set properties after creation.
+ * If we do, the following strawman API might serve us well.
+ *
+ * extern dladm_status_t dladm_overlay_prop_lookup(dladm_handle_t,
+ * datalink_id_t, const char *, dladm_overlay_propinfo_handle_t *);
+ * extern void dladm_overlay_prop_handle_free(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *);
+ * extern dladm_status_t dladm_overlay_set_prop(dladm_handle_t, datalink_id_t,
+ * dladm_propinfo_handle_t, void *buf, size_t *bufsize);
+ * extern dladm_status_t dladm_overlay_str_to_buf(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *, const char *, void *, size_t *);
+ * extern dladm_status_t dladm_overlay_buf_to_str(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *, const void *, const size_t, char *,
+ * size_t *);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBDLOVERLAY_H */
diff --git a/usr/src/lib/libdladm/common/libdlvlan.c b/usr/src/lib/libdladm/common/libdlvlan.c
index 943728dc03..34c1e6682d 100644
--- a/usr/src/lib/libdladm/common/libdlvlan.c
+++ b/usr/src/lib/libdladm/common/libdlvlan.c
@@ -64,7 +64,7 @@ dladm_vlan_create(dladm_handle_t handle, const char *vlan, datalink_id_t linkid,
{
return (dladm_vnic_create(handle, vlan, linkid,
VNIC_MAC_ADDR_TYPE_PRIMARY, NULL, 0, NULL, 0, vid, VRRP_VRID_NONE,
- AF_UNSPEC, vlan_id_out, proplist, flags | DLADM_OPT_VLAN));
+ AF_UNSPEC, vlan_id_out, proplist, NULL, flags | DLADM_OPT_VLAN));
}
/*
diff --git a/usr/src/lib/libdladm/common/libdlvnic.c b/usr/src/lib/libdladm/common/libdlvnic.c
index 44f8bb2726..47d007a1e2 100644
--- a/usr/src/lib/libdladm/common/libdlvnic.c
+++ b/usr/src/lib/libdladm/common/libdlvnic.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
*/
#include <stdio.h>
@@ -399,7 +400,7 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
- uint32_t flags)
+ dladm_errlist_t *errs, uint32_t flags)
{
dladm_vnic_attr_t attr;
datalink_id_t vnic_id;
@@ -539,27 +540,40 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
vnic_created = B_TRUE;
/* Save vnic configuration and its properties */
- if (!(flags & DLADM_OPT_PERSIST))
- goto done;
+ if (flags & DLADM_OPT_PERSIST) {
+ status = dladm_vnic_persist_conf(handle, name, &attr, class);
+ if (status == DLADM_STATUS_OK)
+ conf_set = B_TRUE;
+ }
- status = dladm_vnic_persist_conf(handle, name, &attr, class);
- if (status != DLADM_STATUS_OK)
- goto done;
- conf_set = B_TRUE;
+done:
+ if (status == DLADM_STATUS_OK && proplist != NULL) {
+ uint32_t flg;
+
+ flg = flags & (DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
- if (proplist != NULL) {
for (i = 0; i < proplist->al_count; i++) {
dladm_arg_info_t *aip = &proplist->al_info[i];
+ if (strcmp(aip->ai_name, "zone") == 0 &&
+ flags & DLADM_OPT_TRANSIENT)
+ flg |= DLADM_OPT_TRANSIENT;
+ else
+ flg &= ~DLADM_OPT_TRANSIENT;
+
status = dladm_set_linkprop(handle, vnic_id,
- aip->ai_name, aip->ai_val, aip->ai_count,
- DLADM_OPT_PERSIST);
- if (status != DLADM_STATUS_OK)
+ aip->ai_name, aip->ai_val, aip->ai_count, flg);
+ if (status != DLADM_STATUS_OK) {
+ char errmsg[DLADM_STRSIZE];
+ (void) dladm_errlist_append(errs,
+ "failed to set property %s: %s",
+ aip->ai_name,
+ dladm_status2str(status, errmsg));
break;
+ }
}
}
-done:
if (status != DLADM_STATUS_OK) {
if (conf_set)
(void) dladm_remove_conf(handle, vnic_id);
diff --git a/usr/src/lib/libdladm/common/libdlvnic.h b/usr/src/lib/libdladm/common/libdlvnic.h
index 94b656aadf..839b2de9f2 100644
--- a/usr/src/lib/libdladm/common/libdlvnic.h
+++ b/usr/src/lib/libdladm/common/libdlvnic.h
@@ -55,7 +55,8 @@ typedef struct dladm_vnic_attr {
extern dladm_status_t dladm_vnic_create(dladm_handle_t, const char *,
datalink_id_t, vnic_mac_addr_type_t, uchar_t *,
uint_t, int *, uint_t, uint16_t, vrid_t, int,
- datalink_id_t *, dladm_arg_list_t *, uint32_t);
+ datalink_id_t *, dladm_arg_list_t *,
+ dladm_errlist_t *, uint32_t);
extern dladm_status_t dladm_vnic_delete(dladm_handle_t, datalink_id_t,
uint32_t);
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
index 342584b488..338ccc428e 100644
--- a/usr/src/lib/libdladm/common/linkprop.c
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Joyent, Inc.
* Copyright 2015 Garrett D'Amore <garrett@damore.org>
*/
@@ -881,7 +881,8 @@ static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
datalink_class_t, uint32_t, prop_desc_t *, char **,
uint_t, uint_t);
static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
- const char *, char **, uint_t, uint_t);
+ const char *, char **, uint_t, uint_t,
+ datalink_class_t, uint32_t);
static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
datalink_id_t, datalink_media_t, uint_t);
@@ -1013,19 +1014,13 @@ done:
static dladm_status_t
i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
- const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
+ const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags,
+ datalink_class_t class, uint32_t media)
{
int i;
boolean_t found = B_FALSE;
- datalink_class_t class;
- uint32_t media;
dladm_status_t status = DLADM_STATUS_OK;
- status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
- NULL, 0);
- if (status != DLADM_STATUS_OK)
- return (status);
-
for (i = 0; i < DLADM_MAX_PROPS; i++) {
prop_desc_t *pdp = &prop_table[i];
dladm_status_t s;
@@ -1041,6 +1036,19 @@ i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
status = s;
break;
} else {
+ /*
+ * Some consumers of this function pass a
+ * prop_name of NULL to indicate that all
+ * properties should reset to their default
+ * value. Some properties don't support a
+ * default value and will return NOTSUP -- for
+ * the purpose of resetting property values we
+ * treat it the same as success. We need the
+ * separate status variable 's' so that we can
+ * record any failed calls in 'status' and
+ * continue resetting the rest of the
+ * properties.
+ */
if (s != DLADM_STATUS_OK &&
s != DLADM_STATUS_NOTSUP)
status = s;
@@ -1066,6 +1074,9 @@ dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
{
dladm_status_t status = DLADM_STATUS_OK;
+ datalink_class_t class;
+ uint32_t media;
+ uint32_t link_flags;
if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
(prop_val == NULL && val_cnt > 0) ||
@@ -1078,12 +1089,21 @@ dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
* Check for valid link property against the flags passed
* and set the link property when active flag is passed.
*/
+ status = dladm_datalink_id2info(handle, linkid, &link_flags, &class,
+ &media, NULL, 0);
+ if (status != DLADM_STATUS_OK)
+ return (status);
status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
- val_cnt, flags);
+ val_cnt, flags, class, media);
if (status != DLADM_STATUS_OK)
return (status);
- if (flags & DLADM_OPT_PERSIST) {
+ /*
+ * Write an entry to the persistent configuration database if
+ * and only if the user has requested the property to be
+ * persistent and the link is a persistent link.
+ */
+ if ((flags & DLADM_OPT_PERSIST) && (link_flags & DLMGMT_PERSIST)) {
status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
prop_val, val_cnt);
@@ -1631,6 +1651,9 @@ set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
if (zid_new == zid_old)
return (DLADM_STATUS_OK);
+ if (flags & DLADM_OPT_TRANSIENT)
+ dzp->diz_transient = B_TRUE;
+
if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
flags, media)) != DLADM_STATUS_OK)
return (status);
diff --git a/usr/src/lib/libdladm/common/llib-ldladm b/usr/src/lib/libdladm/common/llib-ldladm
index 8e5eac0614..e5366fb92d 100644
--- a/usr/src/lib/libdladm/common/llib-ldladm
+++ b/usr/src/lib/libdladm/common/llib-ldladm
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
/*LINTLIBRARY*/
@@ -38,3 +39,4 @@
#include <libdlether.h>
#include <libdlsim.h>
#include <libdlbridge.h>
+#include <libdloverlay.h>
diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers
index 63a86529fc..589bbf5330 100644
--- a/usr/src/lib/libdladm/common/mapfile-vers
+++ b/usr/src/lib/libdladm/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
#
@@ -134,6 +135,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
dladm_remap_datalink_id;
dladm_up_datalink_id;
dladm_name2info;
+ dladm_zname2info;
dladm_datalink_id2info;
dladm_walk_datalink_id;
dladm_create_conf;
@@ -269,6 +271,23 @@ SYMBOL_VERSION SUNWprivate_1.1 {
dladm_strs2range;
dladm_range2list;
dladm_list2range;
+
+ dladm_errlist_init;
+ dladm_errlist_reset;
+ dladm_errlist_append;
+
+ dladm_overlay_create;
+ dladm_overlay_delete;
+ dladm_overlay_status;
+ dladm_overlay_prop_info;
+ dladm_overlay_get_prop;
+ dladm_overlay_walk_prop;
+
+ dladm_overlay_cache_set;
+ dladm_overlay_cache_get;
+ dladm_overlay_cache_delete;
+ dladm_overlay_cache_flush;
+ dladm_overlay_walk_cache;
local:
*;
};
diff --git a/usr/src/lib/libdlpi/common/libdlpi.c b/usr/src/lib/libdlpi/common/libdlpi.c
index 1a639a5db9..d07eea70e7 100644
--- a/usr/src/lib/libdlpi/common/libdlpi.c
+++ b/usr/src/lib/libdlpi/common/libdlpi.c
@@ -22,6 +22,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
/*
* Data-Link Provider Interface (Version 2)
@@ -51,7 +54,7 @@
#include "libdlpi_impl.h"
-static int i_dlpi_open(const char *, int *, uint_t, boolean_t);
+static int i_dlpi_open(const char *, const char *, int *, uint_t, boolean_t);
static int i_dlpi_style1_open(dlpi_impl_t *);
static int i_dlpi_style2_open(dlpi_impl_t *);
static int i_dlpi_checkstyle(dlpi_impl_t *, t_uscalar_t);
@@ -130,7 +133,8 @@ dlpi_walk(dlpi_walkfunc_t *fn, void *arg, uint_t flags)
}
int
-dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
+dlpi_open_zone(const char *linkname, const char *zonename, dlpi_handle_t *dhp,
+ uint_t flags)
{
int retval, on = 1;
ifspec_t ifsp;
@@ -164,6 +168,16 @@ dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
if (getenv("DLPI_DEVONLY") != NULL)
dip->dli_oflags |= DLPI_DEVONLY;
+ if (zonename == NULL) {
+ dip->dli_zonename[0] = '\0';
+ } else {
+ if (strlcpy(dip->dli_zonename, zonename,
+ sizeof (dip->dli_zonename)) >= sizeof (dip->dli_zonename)) {
+ free(dip);
+ return (DLPI_EZONENAMEINVAL);
+ }
+ }
+
/* Copy linkname provided to the function. */
if (strlcpy(dip->dli_linkname, linkname, sizeof (dip->dli_linkname)) >=
sizeof (dip->dli_linkname)) {
@@ -237,6 +251,12 @@ dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
return (DLPI_SUCCESS);
}
+int
+dlpi_open(const char *linkname, dlpi_handle_t *dhp, uint_t flags)
+{
+ return (dlpi_open_zone(linkname, NULL, dhp, flags));
+}
+
void
dlpi_close(dlpi_handle_t dh)
{
@@ -1013,6 +1033,15 @@ dlpi_iftype(uint_t dlpitype)
* /dev - if DLPI_DEVONLY is specified, or if there is no
* data-link with the specified name (could be /dev/ip)
*
+ * If a zone's name has been specified, eg. via dlpi_open_zone, then we instead
+ * will check in:
+ *
+ * /dev/ipnet/zone/%z/ - if DLPI_DEVIPNET is specified
+ * /dev/net/zone/%z/ - if a data-link with the specified name exists.
+ *
+ * When a zone name is specified, all of the fallback procedures that we opt for
+ * in the normal case are not used.
+ *
* In particular, if DLPI_DEVIPNET is not specified, this function is used to
* open a data-link node, or "/dev/ip" node. It is usually be called firstly
* with style1 being B_TRUE, and if that fails and the return value is not
@@ -1040,7 +1069,8 @@ dlpi_iftype(uint_t dlpitype)
* the second style-2 open attempt.
*/
static int
-i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
+i_dlpi_open(const char *provider, const char *zonename, int *fd, uint_t flags,
+ boolean_t style1)
{
char path[MAXPATHLEN];
int oflags;
@@ -1051,11 +1081,19 @@ i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
oflags |= O_EXCL;
if (flags & DLPI_DEVIPNET) {
- (void) snprintf(path, sizeof (path), "/dev/ipnet/%s", provider);
- if ((*fd = open(path, oflags)) != -1)
+ if (*zonename != '\0') {
+ (void) snprintf(path, sizeof (path),
+ "/dev/ipnet/zone/%s/%s", zonename, provider);
+ } else {
+ (void) snprintf(path, sizeof (path), "/dev/ipnet/%s",
+ provider);
+ }
+ if ((*fd = open(path, oflags)) != -1) {
return (DLPI_SUCCESS);
- else
- return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
+ } else {
+ return (errno == ENOENT || errno == EISDIR ?
+ DLPI_ENOLINK : DL_SYSERR);
+ }
} else if (style1 && !(flags & DLPI_DEVONLY)) {
char driver[DLPI_LINKNAME_MAX];
char device[DLPI_LINKNAME_MAX];
@@ -1070,7 +1108,13 @@ i_dlpi_open(const char *provider, int *fd, uint_t flags, boolean_t style1)
if (dlpi_parselink(provider, driver, &ppa) != DLPI_SUCCESS)
goto fallback;
- (void) snprintf(path, sizeof (path), "/dev/net/%s", provider);
+ if (*zonename != '\0') {
+ (void) snprintf(path, sizeof (path),
+ "/dev/net/zone/%s/%s", zonename, provider);
+ } else {
+ (void) snprintf(path, sizeof (path), "/dev/net/%s",
+ provider);
+ }
if ((*fd = open(path, oflags)) != -1)
return (DLPI_SUCCESS);
@@ -1118,7 +1162,7 @@ fallback:
if ((*fd = open(path, oflags)) != -1)
return (DLPI_SUCCESS);
- return (errno == ENOENT ? DLPI_ENOLINK : DL_SYSERR);
+ return (errno == ENOENT || errno == EISDIR ? DLPI_ENOLINK : DL_SYSERR);
}
/*
@@ -1130,7 +1174,8 @@ i_dlpi_style1_open(dlpi_impl_t *dip)
int retval, save_errno;
int fd;
- retval = i_dlpi_open(dip->dli_linkname, &fd, dip->dli_oflags, B_TRUE);
+ retval = i_dlpi_open(dip->dli_linkname, dip->dli_zonename, &fd,
+ dip->dli_oflags, B_TRUE);
if (retval != DLPI_SUCCESS)
return (retval);
dip->dli_fd = fd;
@@ -1153,7 +1198,8 @@ i_dlpi_style2_open(dlpi_impl_t *dip)
int fd;
int retval, save_errno;
- retval = i_dlpi_open(dip->dli_provider, &fd, dip->dli_oflags, B_FALSE);
+ retval = i_dlpi_open(dip->dli_provider, dip->dli_zonename, &fd,
+ dip->dli_oflags, B_FALSE);
if (retval != DLPI_SUCCESS)
return (retval);
dip->dli_fd = fd;
@@ -1571,7 +1617,8 @@ static const char *libdlpi_errlist[] = {
/* DLPI_ENOTENOTSUP */
"invalid DLPI notification type", /* DLPI_ENOTEINVAL */
"invalid DLPI notification id", /* DLPI_ENOTEIDINVAL */
- "DLPI_IPNETINFO not supported" /* DLPI_EIPNETINFONOTSUP */
+ "DLPI_IPNETINFO not supported", /* DLPI_EIPNETINFONOTSUP */
+ "invalid zone name" /* DLPI_EZONENAMEINVAL */
};
const char *
diff --git a/usr/src/lib/libdlpi/common/libdlpi.h b/usr/src/lib/libdlpi/common/libdlpi.h
index 993ac1b7a4..364413ee3a 100644
--- a/usr/src/lib/libdlpi/common/libdlpi.h
+++ b/usr/src/lib/libdlpi/common/libdlpi.h
@@ -93,6 +93,7 @@ enum {
DLPI_ENOTENOTSUP, /* DLPI notification not supported by link */
DLPI_ENOTEIDINVAL, /* invalid DLPI notification id */
DLPI_EIPNETINFONOTSUP, /* DLPI_IPNETINFO not supported */
+ DLPI_EZONENAMEINVAL, /* invalid zone name */
DLPI_ERRMAX /* Highest + 1 libdlpi error code */
};
@@ -184,6 +185,7 @@ typedef boolean_t dlpi_walkfunc_t(const char *, void *);
extern void dlpi_walk(dlpi_walkfunc_t *, void *, uint_t);
extern int dlpi_open(const char *, dlpi_handle_t *, uint_t);
+extern int dlpi_open_zone(const char *, const char *, dlpi_handle_t *, uint_t);
extern void dlpi_close(dlpi_handle_t);
extern int dlpi_info(dlpi_handle_t, dlpi_info_t *, uint_t);
extern int dlpi_bind(dlpi_handle_t, uint_t, uint_t *);
diff --git a/usr/src/lib/libdlpi/common/libdlpi_impl.h b/usr/src/lib/libdlpi/common/libdlpi_impl.h
index 70708ff5af..8969cce7cb 100644
--- a/usr/src/lib/libdlpi/common/libdlpi_impl.h
+++ b/usr/src/lib/libdlpi/common/libdlpi_impl.h
@@ -28,6 +28,7 @@
#include <libdlpi.h>
#include <sys/sysmacros.h>
+#include <sys/zone.h>
#ifdef __cplusplus
extern "C" {
@@ -112,6 +113,8 @@ typedef struct dlpi_impl_s {
/* full linkname including PPA */
char dli_provider[DLPI_LINKNAME_MAX];
/* only provider name */
+ char dli_zonename[ZONENAME_MAX];
+ /* optionally specified zone */
t_uscalar_t dli_style; /* style 1 or 2 */
uint_t dli_saplen; /* bound SAP length */
uint_t dli_sap; /* bound SAP value */
diff --git a/usr/src/lib/libdlpi/common/mapfile-vers b/usr/src/lib/libdlpi/common/mapfile-vers
index ed3231dc92..c818e5e660 100644
--- a/usr/src/lib/libdlpi/common/mapfile-vers
+++ b/usr/src/lib/libdlpi/common/mapfile-vers
@@ -67,6 +67,11 @@ SYMBOL_VERSION SUNW_1.1 { # first release of libdlpi, Solaris 11
SYMBOL_VERSION SUNWprivate {
global:
+ #
+ # dlpi_open_zone should be moved to a new public section once it is
+ # upstreamed into illumos-gate .
+ #
+ dlpi_open_zone;
dlpi_parselink;
dlpi_makelink;
dlpi_style;
diff --git a/usr/src/lib/libdns_sd/java/com/apple/dnssd/DNSSDRecordRegistrar.java b/usr/src/lib/libdns_sd/java/com/apple/dnssd/DNSSDRecordRegistrar.java
index 62c5330840..569c51dd3a 100644
--- a/usr/src/lib/libdns_sd/java/com/apple/dnssd/DNSSDRecordRegistrar.java
+++ b/usr/src/lib/libdns_sd/java/com/apple/dnssd/DNSSDRecordRegistrar.java
@@ -5,9 +5,9 @@
* 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.
@@ -23,7 +23,7 @@ package com.apple.dnssd;
public interface DNSSDRecordRegistrar extends DNSSDService
{
- /** Register an independent {@link DNSRecord}.<P>
+ /** Register an independent {@link DNSRecord}.<P>
@param flags
Possible values are SHARED or UNIQUE (see flag type definitions for details).
<P>
@@ -40,7 +40,7 @@ public interface DNSSDRecordRegistrar extends DNSSDService
as defined in nameser.h.
<P>
@param rrclass
- The class of the resource record, as defined in nameser.h
+ The class of the resource record, as defined in nameser.h
(usually 1 for the Internet class).
<P>
@param rdata
@@ -54,8 +54,8 @@ public interface DNSSDRecordRegistrar extends DNSSDService
@throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
@see RuntimePermission
*/
- public DNSRecord registerRecord( int flags, int ifIndex, String fullname, int rrtype,
+ public DNSRecord registerRecord( int flags, int ifIndex, String fullname, int rrtype,
int rrclass, byte[] rdata, int ttl)
throws DNSSDException;
-}
+}
diff --git a/usr/src/lib/libdtrace/Makefile.com b/usr/src/lib/libdtrace/Makefile.com
index dead7c1468..d8aa13e4dc 100644
--- a/usr/src/lib/libdtrace/Makefile.com
+++ b/usr/src/lib/libdtrace/Makefile.com
@@ -87,6 +87,7 @@ DLIBSRCS += \
io.d \
ip.d \
iscsit.d \
+ mac.d \
net.d \
nfs.d \
nfssrv.d \
@@ -99,7 +100,8 @@ DLIBSRCS += \
sysevent.d \
tcp.d \
udp.d \
- unistd.d
+ unistd.d \
+ vnd.d
include ../../Makefile.lib
@@ -112,6 +114,7 @@ CLEANFILES += dt_lex.c dt_grammar.c dt_grammar.h y.output
CLEANFILES += ../common/procfs.sed ../common/procfs.d
CLEANFILES += ../common/io.sed ../common/io.d
CLEANFILES += ../common/ip.sed ../common/ip.d
+CLEANFILES += ../common/mac.sed ../common/mac.d
CLEANFILES += ../common/net.sed ../common/net.d
CLEANFILES += ../common/errno.d ../common/signal.d
CLEANFILES += ../common/dt_errtags.c ../common/dt_names.c
@@ -133,7 +136,7 @@ CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-switch
YYCFLAGS =
-LDLIBS += -lgen -lproc -lrtld_db -lnsl -lsocket -lctf -lelf -lc
+LDLIBS += -lgen -lproc -lrtld_db -lnsl -lsocket -lctf -lelf -lc -lzonecfg
DRTILDLIBS = $(LDLIBS.lib) -lc
LIBDAUDITLIBS = $(LDLIBS.lib) -lmapmalloc -lc -lproc
@@ -205,6 +208,9 @@ pics/dt_lex.o pics/dt_grammar.o := CCVERBOSE =
../common/ip.d: ../common/ip.sed ../common/ip.d.in
sed -f ../common/ip.sed < ../common/ip.d.in > $@
+../common/mac.d: ../common/mac.sed ../common/mac.d.in
+ sed -f ../common/mac.sed < ../common/mac.d.in > $@
+
../common/net.d: ../common/net.sed ../common/net.d.in
sed -f ../common/net.sed < ../common/net.d.in > $@
diff --git a/usr/src/lib/libdtrace/common/dt_cg.c b/usr/src/lib/libdtrace/common/dt_cg.c
index 28db9b2262..9f3625e6ee 100644
--- a/usr/src/lib/libdtrace/common/dt_cg.c
+++ b/usr/src/lib/libdtrace/common/dt_cg.c
@@ -27,6 +27,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2017 Joyent, Inc.
*/
#include <sys/types.h>
@@ -1115,23 +1116,14 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
}
/*
- * If we are storing to a variable, generate an stv instruction from
- * the variable specified by the identifier. If we are storing to a
- * memory address, generate code again for the left-hand side using
- * DT_NF_REF to get the address, and then generate a store to it.
- * In both paths, we assume dnp->dn_reg already has the new value.
+ * If we are storing to a memory address, generate code again for the
+ * left-hand side using DT_NF_REF to get the address, and then generate
+ * a store to it.
+ *
+ * Both here and the other variable-store paths, we assume dnp->dn_reg
+ * already has the new value.
*/
- if (dnp->dn_left->dn_kind == DT_NODE_VAR) {
- idp = dt_ident_resolve(dnp->dn_left->dn_ident);
-
- if (idp->di_kind == DT_IDENT_ARRAY)
- dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
-
- idp->di_flags |= DT_IDFLG_DIFW;
- instr = DIF_INSTR_STV(dt_cg_stvar(idp),
- idp->di_id, dnp->dn_reg);
- dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
- } else {
+ if (dnp->dn_left->dn_kind != DT_NODE_VAR) {
uint_t rbit = dnp->dn_left->dn_flags & DT_NF_REF;
assert(dnp->dn_left->dn_flags & DT_NF_WRITABLE);
@@ -1145,7 +1137,33 @@ dt_cg_asgn_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dnp->dn_left->dn_flags &= ~DT_NF_REF;
dnp->dn_left->dn_flags |= rbit;
+ return;
}
+
+ idp = dt_ident_resolve(dnp->dn_left->dn_ident);
+ idp->di_flags |= DT_IDFLG_DIFW;
+
+ /*
+ * Storing to an array variable is a special case.
+ * Only 'uregs[]' supports this for the time being.
+ */
+ if (idp->di_kind == DT_IDENT_ARRAY &&
+ idp->di_id <= DIF_VAR_ARRAY_MAX) {
+ dt_node_t *idx = dnp->dn_left->dn_args;
+
+ dt_cg_node(idx, dlp, drp);
+ instr = DIF_INSTR_FMT(DIF_OP_STGA, idp->di_id, idx->dn_reg,
+ dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
+ dt_regset_free(drp, idx->dn_reg);
+ return;
+ }
+
+ if (idp->di_kind == DT_IDENT_ARRAY)
+ dt_cg_arglist(idp, dnp->dn_left->dn_args, dlp, drp);
+
+ instr = DIF_INSTR_STV(dt_cg_stvar(idp), idp->di_id, dnp->dn_reg);
+ dt_irlist_append(dlp, dt_cg_node_alloc(DT_LBL_NONE, instr));
}
static void
diff --git a/usr/src/lib/libdtrace/common/dt_decl.c b/usr/src/lib/libdtrace/common/dt_decl.c
index bbb561d027..c9bd469ddb 100644
--- a/usr/src/lib/libdtrace/common/dt_decl.c
+++ b/usr/src/lib/libdtrace/common/dt_decl.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
- * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015 Joyent, Inc. All rights reserved.
*/
#include <strings.h>
@@ -652,7 +652,7 @@ dt_decl_member(dt_node_t *dnp)
}
if (ctf_add_member(dsp->ds_ctfp, dsp->ds_type,
- ident, dtt.dtt_type) == CTF_ERR) {
+ ident, dtt.dtt_type, ULONG_MAX) == CTF_ERR) {
xyerror(D_UNKNOWN, "failed to define member '%s': %s\n",
idname, ctf_errmsg(ctf_errno(dsp->ds_ctfp)));
}
diff --git a/usr/src/lib/libdtrace/common/dt_dis.c b/usr/src/lib/libdtrace/common/dt_dis.c
index c0af36420e..60195f3970 100644
--- a/usr/src/lib/libdtrace/common/dt_dis.c
+++ b/usr/src/lib/libdtrace/common/dt_dis.c
@@ -27,7 +27,7 @@
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
- * Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2017 Joyent, Inc.
*/
#include <strings.h>
@@ -47,7 +47,7 @@ dt_dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
/*ARGSUSED*/
static void
dt_dis_branch(const dtrace_difo_t *dp, const char *name,
- dif_instr_t in, FILE *fp)
+ dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %u", name, DIF_INSTR_LABEL(in));
}
@@ -63,7 +63,7 @@ dt_dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
/*ARGSUSED*/
static void
dt_dis_store(const dtrace_difo_t *dp, const char *name,
- dif_instr_t in, FILE *fp)
+ dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u, [%%r%u]", name,
DIF_INSTR_R1(in), DIF_INSTR_RD(in));
@@ -167,6 +167,19 @@ dt_dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
}
static void
+dt_dis_sta(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
+{
+ uint_t var = DIF_INSTR_VAR(in);
+ const char *vname;
+
+ (void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u, %%r%u",
+ name, var, DIF_INSTR_R2(in), DIF_INSTR_RD(in));
+
+ if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
+ (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
+}
+
+static void
dt_dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t intptr = DIF_INSTR_INTEGER(in);
@@ -428,6 +441,7 @@ dt_dis(const dtrace_difo_t *dp, FILE *fp)
{ "rldx", dt_dis_load }, /* DIF_OP_RLDX */
{ "xlate", dt_dis_xlate }, /* DIF_OP_XLATE */
{ "xlarg", dt_dis_xlate }, /* DIF_OP_XLARG */
+ { "stga", dt_dis_sta }, /* DIF_OP_XLARG */
};
const struct opent *op;
diff --git a/usr/src/lib/libdtrace/common/dt_impl.h b/usr/src/lib/libdtrace/common/dt_impl.h
index 2681709483..6841eca4e6 100644
--- a/usr/src/lib/libdtrace/common/dt_impl.h
+++ b/usr/src/lib/libdtrace/common/dt_impl.h
@@ -267,6 +267,7 @@ struct dtrace_hdl {
uint_t dt_droptags; /* boolean: set via -xdroptags */
uint_t dt_active; /* boolean: set once tracing is active */
uint_t dt_stopped; /* boolean: set once tracing is stopped */
+ uint_t dt_optset; /* boolean: set once options have been set */
processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
processorid_t dt_endedon; /* CPU that executed END probe (if any) */
uint_t dt_oflags; /* dtrace open-time options (see dtrace.h) */
diff --git a/usr/src/lib/libdtrace/common/dt_link.c b/usr/src/lib/libdtrace/common/dt_link.c
index e910ac3ff1..55d2fbd3bc 100644
--- a/usr/src/lib/libdtrace/common/dt_link.c
+++ b/usr/src/lib/libdtrace/common/dt_link.c
@@ -22,10 +22,9 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2016 Mark Johnston.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#define ELF_TARGET_ALL
#include <elf.h>
@@ -1013,6 +1012,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
static const char dt_enabled[] = "enabled";
static const char dt_symprefix[] = "$dtrace";
static const char dt_symfmt[] = "%s%d.%s";
+ char probename[DTRACE_NAMELEN];
int fd, i, ndx, eprobe, mod = 0;
Elf *elf = NULL;
GElf_Ehdr ehdr;
@@ -1355,8 +1355,6 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
bcopy(s, pname, p - s);
pname[p - s] = '\0';
- p = strhyphenate(p + 3); /* strlen("___") */
-
if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
shdr_rel.sh_info, &fsym) != 0)
goto err;
@@ -1406,9 +1404,17 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
"no such provider %s", pname));
}
- if ((prp = dt_probe_lookup(pvp, p)) == NULL) {
+ /* strlen("___") */
+ if (strlcpy(probename, p + 3, sizeof (probename)) >=
+ sizeof (probename))
+ return (dt_link_error(dtp, elf, fd, bufs,
+ "invalid probe name %s", probename));
+
+ (void) strhyphenate(probename);
+
+ if ((prp = dt_probe_lookup(pvp, probename)) == NULL) {
return (dt_link_error(dtp, elf, fd, bufs,
- "no such probe %s", p));
+ "no such probe %s", probename));
}
assert(fsym.st_value <= rela.r_offset);
diff --git a/usr/src/lib/libdtrace/common/dt_module.c b/usr/src/lib/libdtrace/common/dt_module.c
index 0288f329da..4c9a7ce66b 100644
--- a/usr/src/lib/libdtrace/common/dt_module.c
+++ b/usr/src/lib/libdtrace/common/dt_module.c
@@ -1372,6 +1372,77 @@ dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr,
return (0);
}
+/*
+ * We've been asked to look up something inside a pid related module and it has
+ * been qualified with a library name. In that case, we may have to split this
+ * up into the library and the type itself, which will be separated by an '`'
+ * character. This is complicated further by the fact that the keyword for a
+ * struct, union, or enum, will precede the library. Hence we may have something
+ * that looks like "struct libsocket.so.1`msghdr" in name and we need to
+ * transform that into "libsocket.so.1" and "struct msghdr".
+ */
+int
+dtrace_lookup_fixup_pidtype(const char *name, char **libp, char **typep)
+{
+ int len, i;
+ char *split = NULL, *lib, *buf;
+ char *base;
+ char *keywords[] = { "struct ", "union ", "enum ", NULL };
+
+ if (name == NULL)
+ return (-1);
+
+ *libp = NULL;
+ *typep = NULL;
+ buf = strdup(name);
+ if (buf == NULL)
+ return (-1);
+
+ i = 0;
+ lib = buf;
+ while (keywords[i] != NULL) {
+ base = keywords[i];
+ len = strlen(base);
+ if (strncmp(name, base, len) == 0) {
+ lib += len;
+ break;
+ }
+ i++;
+ }
+
+ split = strchr(buf, '`');
+ assert(split != NULL);
+ *split = '\0';
+ split++;
+ if (lib == buf) {
+ *libp = strdup(buf);
+ *typep = strdup(split);
+ if (*libp == NULL || *typep == NULL)
+ goto err;
+ free(buf);
+ return (0);
+ } else {
+ assert(len > 0);
+ assert(base != NULL);
+
+ *libp = strdup(lib);
+ if (*libp == NULL)
+ goto err;
+ if (asprintf(typep, "%s%s", base, split) == -1)
+ goto err;
+ free(buf);
+ return (0);
+ }
+
+err:
+ free(buf);
+ free(*libp);
+ *libp = NULL;
+ free(*typep);
+ *typep = NULL;
+ return (-1);
+}
+
int
dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
dtrace_typeinfo_t *tip)
@@ -1383,7 +1454,6 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
uint_t n, i;
int justone;
ctf_file_t *fp;
- char *buf, *p, *q;
uint_t mask = 0; /* mask of dt_module flags to match */
uint_t bits = 0; /* flag bits that must be present */
@@ -1437,19 +1507,19 @@ dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
id = ctf_lookup_by_name(dmp->dm_ctfp, name);
fp = dmp->dm_ctfp;
} else {
- if ((p = strchr(name, '`')) != NULL) {
- buf = strdup(name);
- if (buf == NULL)
+ dt_dprintf("Trying to find userland type: %s\n", name);
+ if (strchr(name, '`') != NULL) {
+ char *lib, *type;
+ if (dtrace_lookup_fixup_pidtype(name, &lib,
+ &type) != 0) {
return (dt_set_errno(dtp, EDT_NOMEM));
- p = strchr(buf, '`');
- if ((q = strchr(p + 1, '`')) != NULL)
- p = q;
- *p = '\0';
- fp = dt_module_getctflib(dtp, dmp, buf);
+ }
+ fp = dt_module_getctflib(dtp, dmp, lib);
if (fp == NULL || (id = ctf_lookup_by_name(fp,
- p + 1)) == CTF_ERR)
+ type)) == CTF_ERR)
id = CTF_ERR;
- free(buf);
+ free(lib);
+ free(type);
} else {
for (i = 0; i < dmp->dm_nctflibs; i++) {
fp = dmp->dm_libctfp[i];
diff --git a/usr/src/lib/libdtrace/common/dt_open.c b/usr/src/lib/libdtrace/common/dt_open.c
index 38c8146039..3325f333ab 100644
--- a/usr/src/lib/libdtrace/common/dt_open.c
+++ b/usr/src/lib/libdtrace/common/dt_open.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
*/
@@ -40,6 +40,7 @@
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
+#include <zone.h>
#define _POSIX_PTHREAD_SEMANTICS
#include <dirent.h>
@@ -427,8 +428,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_type, "uid_t" },
{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
-{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
- &dt_idops_regs, NULL },
+{ "uregs", DT_IDENT_ARRAY, DT_IDFLG_WRITE, DIF_VAR_UREGS, DT_ATTR_STABCMN,
+ DT_VERS_1_0, &dt_idops_regs, NULL },
{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "stack(...)" },
{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
@@ -685,8 +686,8 @@ const dtrace_pattr_t _dtrace_prvdesc = {
{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },
};
-const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */
-const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */
+const char *_dtrace_defcpp = "/usr/lib/cpp"; /* default cpp(1) to invoke */
+const char *_dtrace_defld = "/usr/bin/ld"; /* default ld(1) to invoke */
const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */
const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */
@@ -826,6 +827,8 @@ dt_vopen(int version, int flags, int *errp,
dt_provmod_t *provmod = NULL;
int i, err;
struct rlimit rl;
+ const char *zroot;
+ char *libpath = NULL;
const dt_intrinsic_t *dinp;
const dt_typedef_t *dtyp;
@@ -958,11 +961,19 @@ alloc:
dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *));
dt_proc_init(dtp);
dtp->dt_vmax = DT_VERS_LATEST;
- dtp->dt_cpp_path = strdup(_dtrace_defcpp);
+ zroot = zone_get_nroot();
+ if (zroot != NULL) {
+ (void) asprintf(&dtp->dt_ld_path, "%s/%s", zroot,
+ _dtrace_defld);
+ (void) asprintf(&dtp->dt_cpp_path, "%s/%s", zroot,
+ _dtrace_defcpp);
+ } else {
+ dtp->dt_ld_path = strdup(_dtrace_defld);
+ dtp->dt_cpp_path = strdup(_dtrace_defcpp);
+ }
dtp->dt_cpp_argv = malloc(sizeof (char *));
dtp->dt_cpp_argc = 1;
dtp->dt_cpp_args = 1;
- dtp->dt_ld_path = strdup(_dtrace_defld);
dtp->dt_provmod = provmod;
dtp->dt_vector = vector;
dtp->dt_varg = arg;
@@ -1136,13 +1147,13 @@ alloc:
* Add intrinsic pointer types that are needed to initialize printf
* format dictionary types (see table in dt_printf.c).
*/
- (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, NULL,
ctf_lookup_by_name(dmp->dm_ctfp, "void"));
- (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, NULL,
ctf_lookup_by_name(dmp->dm_ctfp, "char"));
- (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT,
+ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, NULL,
ctf_lookup_by_name(dmp->dm_ctfp, "int"));
if (ctf_update(dmp->dm_ctfp) != 0) {
@@ -1202,11 +1213,11 @@ alloc:
ctc.ctc_argc = 0;
ctc.ctc_flags = 0;
- dtp->dt_type_func = ctf_add_function(dmp->dm_ctfp,
+ dtp->dt_type_func = ctf_add_funcptr(dmp->dm_ctfp,
CTF_ADD_ROOT, &ctc, NULL);
- dtp->dt_type_fptr = ctf_add_pointer(dmp->dm_ctfp,
- CTF_ADD_ROOT, dtp->dt_type_func);
+ dtp->dt_type_fptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, NULL,
+ dtp->dt_type_func);
/*
* We also insert CTF definitions for the special D intrinsic types
@@ -1307,9 +1318,15 @@ alloc:
* compile, and to provide better error reporting (because the full
* reporting of compiler errors requires dtrace_open() to succeed).
*/
- if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
+ if (zroot != NULL)
+ (void) asprintf(&libpath, "%s/%s", zroot, _dtrace_libdir);
+ if (dtrace_setopt(dtp, "libdir",
+ libpath != NULL ? libpath : _dtrace_libdir) != 0)
return (set_open_errno(dtp, errp, dtp->dt_errno));
+ if (libpath != NULL)
+ free(libpath);
+
return (dtp);
}
diff --git a/usr/src/lib/libdtrace/common/dt_options.c b/usr/src/lib/libdtrace/common/dt_options.c
index 201b50a177..be985d6dab 100644
--- a/usr/src/lib/libdtrace/common/dt_options.c
+++ b/usr/src/lib/libdtrace/common/dt_options.c
@@ -41,6 +41,8 @@
#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
+#include <zone.h>
+#include <libzonecfg.h>
#include <dt_impl.h>
#include <dt_string.h>
@@ -854,6 +856,44 @@ dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
return (0);
}
+/*ARGSUSED*/
+static int
+dt_opt_zone(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+ zoneid_t z, did;
+
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ /*
+ * If the specified zone is currently running, we'll query the kernel
+ * for its debugger ID. If it doesn't appear to be running, we'll look
+ * for it for among all installed zones (thereby allowing a zdefs
+ * enabling against a halted zone).
+ */
+ if ((z = getzoneidbyname(arg)) != -1) {
+ if (zone_getattr(z, ZONE_ATTR_DID, &did, sizeof (did)) < 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+ } else {
+ zone_dochandle_t handle;
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ return (dt_set_errno(dtp, errno));
+
+ if (zonecfg_get_handle(arg, handle) != Z_OK) {
+ zonecfg_fini_handle(handle);
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+ }
+
+ did = zonecfg_get_did(handle);
+ zonecfg_fini_handle(handle);
+ }
+
+ dtp->dt_options[DTRACEOPT_ZONE] = did;
+
+ return (0);
+}
+
int
dt_options_load(dtrace_hdl_t *dtp)
{
@@ -988,6 +1028,7 @@ static const dt_option_t _dtrace_rtoptions[] = {
{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
+ { "zone", dt_opt_zone, DTRACEOPT_ZONE },
{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
{ NULL }
};
@@ -1068,9 +1109,41 @@ dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
if (dtp->dt_active)
return (dt_set_errno(dtp, EDT_ACTIVE));
+ /*
+ * If our options had been previously ioctl'd down,
+ * clear dt_optset to indicate that a run-time option
+ * has since been set.
+ */
+ dtp->dt_optset = B_FALSE;
+
return (op->o_func(dtp, val, op->o_option));
}
}
return (dt_set_errno(dtp, EDT_BADOPTNAME));
}
+
+int
+dtrace_setopts(dtrace_hdl_t *dtp)
+{
+ void *dof;
+ int err;
+
+ if (dtp->dt_optset)
+ return (0);
+
+ if ((dof = dtrace_getopt_dof(dtp)) == NULL)
+ return (-1); /* dt_errno has been set for us */
+
+ if ((err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof)) == -1)
+ (void) dt_set_errno(dtp, errno);
+
+ dtrace_dof_destroy(dtp, dof);
+
+ if (err == -1)
+ return (-1);
+
+ dtp->dt_optset = B_TRUE;
+
+ return (0);
+}
diff --git a/usr/src/lib/libdtrace/common/dt_parser.c b/usr/src/lib/libdtrace/common/dt_parser.c
index 7f771a8079..e652f337d9 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.c
+++ b/usr/src/lib/libdtrace/common/dt_parser.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent Inc. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
*/
@@ -288,7 +288,7 @@ dt_type_pointer(dtrace_typeinfo_t *tip)
return (dt_set_errno(dtp, EDT_CTF));
}
- ptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, type);
+ ptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, NULL, type);
if (ptr == CTF_ERR || ctf_update(dmp->dm_ctfp) == CTF_ERR) {
dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
diff --git a/usr/src/lib/libdtrace/common/dt_program.c b/usr/src/lib/libdtrace/common/dt_program.c
index 7d725bd0af..e4f9d8dd1c 100644
--- a/usr/src/lib/libdtrace/common/dt_program.c
+++ b/usr/src/lib/libdtrace/common/dt_program.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
*/
@@ -154,6 +155,14 @@ dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
void *dof;
int n, err;
+ /*
+ * If we have not yet ioctl'd down our options DOF, we'll do that
+ * before enabling any probes (some options will affect which probes
+ * we match).
+ */
+ if (dtrace_setopts(dtp) != 0)
+ return (-1);
+
dtrace_program_info(dtp, pgp, pip);
if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
diff --git a/usr/src/lib/libdtrace/common/dt_work.c b/usr/src/lib/libdtrace/common/dt_work.c
index 97a7f62d69..c330394027 100644
--- a/usr/src/lib/libdtrace/common/dt_work.c
+++ b/usr/src/lib/libdtrace/common/dt_work.c
@@ -25,7 +25,9 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ */
#include <dt_impl.h>
#include <stddef.h>
@@ -164,13 +166,22 @@ dtrace_status(dtrace_hdl_t *dtp)
int
dtrace_go(dtrace_hdl_t *dtp)
{
- void *dof;
- int err;
-
if (dtp->dt_active)
return (dt_set_errno(dtp, EINVAL));
/*
+ * In most cases, we will have already ioctl'd down our options DOF
+ * by this point -- but if a libdtrace does a dtrace_setopt() after
+ * calling dtrace_program_exec() but before calling dtrace_go(),
+ * dt_optset will be cleared and we need to ioctl down the options
+ * DOF now.
+ */
+ if (dtrace_setopts(dtp) != 0 &&
+ (dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL)) {
+ return (-1);
+ }
+
+ /*
* If a dtrace:::ERROR program and callback are registered, enable the
* program before we start tracing. If this fails for a vector open
* with ENOTTY, we permit dtrace_go() to succeed so that vector clients
@@ -178,19 +189,10 @@ dtrace_go(dtrace_hdl_t *dtp)
* though they do not provide support for the DTRACEIOC_ENABLE ioctl.
*/
if (dtp->dt_errprog != NULL &&
- dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
- dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
- return (-1); /* dt_errno has been set for us */
-
- if ((dof = dtrace_getopt_dof(dtp)) == NULL)
+ dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 &&
+ (dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
return (-1); /* dt_errno has been set for us */
- err = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof);
- dtrace_dof_destroy(dtp, dof);
-
- if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
- return (dt_set_errno(dtp, errno));
-
if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
if (errno == EACCES)
return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
diff --git a/usr/src/lib/libdtrace/common/dtrace.h b/usr/src/lib/libdtrace/common/dtrace.h
index 293ab944af..dd591296aa 100644
--- a/usr/src/lib/libdtrace/common/dtrace.h
+++ b/usr/src/lib/libdtrace/common/dtrace.h
@@ -83,6 +83,7 @@ extern const char *dtrace_subrstr(dtrace_hdl_t *, int);
extern int dtrace_setopt(dtrace_hdl_t *, const char *, const char *);
extern int dtrace_getopt(dtrace_hdl_t *, const char *, dtrace_optval_t *);
+extern int dtrace_setopts(dtrace_hdl_t *);
extern void dtrace_update(dtrace_hdl_t *);
extern int dtrace_ctlfd(dtrace_hdl_t *);
diff --git a/usr/src/lib/libdtrace/common/mac.d.in b/usr/src/lib/libdtrace/common/mac.d.in
new file mode 100644
index 0000000000..6263d51bdd
--- /dev/null
+++ b/usr/src/lib/libdtrace/common/mac.d.in
@@ -0,0 +1,66 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#pragma D depends_on library ip.d
+
+inline int ETHERTYPE_PUP = @ETHERTYPE_PUP@;
+inline int ETHERTYPE_802_MIN = @ETHERTYPE_802_MIN@;
+inline int ETHERTYPE_IP = @ETHERTYPE_IP@;
+inline int ETHERTYPE_ARP = @ETHERTYPE_ARP@;
+inline int ETHERTYPE_REVARP = @ETHERTYPE_REVARP@;
+inline int ETHERTYPE_AT = @ETHERTYPE_AT@;
+inline int ETHERTYPE_AARP = @ETHERTYPE_AARP@;
+inline int ETHERTYPE_VLAN = @ETHERTYPE_VLAN@;
+inline int ETHERTYPE_IPV6 = @ETHERTYPE_IPV6@;
+inline int ETHERTYPE_SLOW = @ETHERTYPE_SLOW@;
+inline int ETHERTYPE_PPPOED = @ETHERTYPE_PPPOED@;
+inline int ETHERTYPE_PPPOES = @ETHERTYPE_PPPOES@;
+inline int ETHERTYPE_EAPOL = @ETHERTYPE_EAPOL@;
+inline int ETHERTYPE_RSN_PREAUTH = @ETHERTYPE_RSN_PREAUTH@;
+inline int ETHERTYPE_TRILL = @ETHERTYPE_TRILL@;
+inline int ETHERTYPE_FCOE = @ETHERTYPE_FCOE@;
+inline int ETHERTYPE_MAX = @ETHERTYPE_MAX@;
+
+
+typedef struct etherinfo {
+ uint8_t eth_dst[6]; /* Destination MAC addr */
+ uint8_t eth_src[6]; /* Source MAC addr */
+ uint16_t eth_type; /* Ethertype */
+ boolean_t eth_istagged; /* Is the VLAN tag present */
+ uint8_t eth_priority; /* Priority tag */
+ uint8_t eth_dei; /* drop eligible indicator */
+ uint16_t eth_vlanid; /* VLAN ID */
+ uintptr_t eth_header; /* Pointer to start of header */
+ uintptr_t eth_mblk; /* Pointer to the mblk containing header */
+} etherinfo_t;
+
+#pragma D binding "1.12.1" translator
+translator etherinfo_t < mblk_t *mp > {
+ eth_dst = mp->b_rptr;
+ eth_src = mp->b_rptr + 6;
+ eth_type = ntohs(*(uint16_t *)(mp->b_rptr + 12)) == ETHERTYPE_VLAN ?
+ ntohs(*(uint16_t *)(mp->b_rptr + 16)) :
+ ntohs(*(uint16_t *)(mp->b_rptr + 12));
+ eth_istagged = ntohs(*(uint16_t *)(mp->b_rptr + 12)) == ETHERTYPE_VLAN ?
+ 1 : 0;
+ eth_priority = ntohs(*(uint16_t *)(mp->b_rptr + 12)) == ETHERTYPE_VLAN ?
+ ntohs(*(uint16_t *)(mp->b_rptr + 14)) & 0xe000: 0;
+ eth_dei = ntohs(*(uint16_t *)(mp->b_rptr + 12)) == ETHERTYPE_VLAN ?
+ ntohs(*(uint16_t *)(mp->b_rptr + 14)) & 0x1000: 0;
+ eth_vlanid = ntohs(*(uint16_t *)(mp->b_rptr + 12)) == ETHERTYPE_VLAN ?
+ ntohs(*(uint16_t *)(mp->b_rptr + 14)) & 0x0fff: 0;
+ eth_header = (uintptr_t)mp->b_rptr;
+ eth_mblk = (uintptr_t)mp;
+};
diff --git a/usr/src/lib/libdtrace/common/mac.sed.in b/usr/src/lib/libdtrace/common/mac.sed.in
new file mode 100644
index 0000000000..00e149d000
--- /dev/null
+++ b/usr/src/lib/libdtrace/common/mac.sed.in
@@ -0,0 +1,45 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+
+/*
+ * This file is a sed script which is first preprocessed by cpp or cc -E to
+ * define a set of sed directives which replace #define tokens with their
+ * values. After preprocessing, the sed script is run over vnd.d.in to
+ * replace the #define tokens listed below to create the finished vnd.d.
+ * Refer to the rules in libdtrace/Makefile.com for more information.
+ */
+
+#include <sys/ethernet.h>
+
+#define SED_REPLACE(x) s/#x/x/g
+
+SED_REPLACE(ETHERTYPE_PUP)
+SED_REPLACE(ETHERTYPE_802_MIN)
+SED_REPLACE(ETHERTYPE_IP)
+SED_REPLACE(ETHERTYPE_ARP)
+SED_REPLACE(ETHERTYPE_REVARP)
+SED_REPLACE(ETHERTYPE_AT)
+SED_REPLACE(ETHERTYPE_AARP)
+SED_REPLACE(ETHERTYPE_VLAN)
+SED_REPLACE(ETHERTYPE_IPV6)
+SED_REPLACE(ETHERTYPE_SLOW)
+SED_REPLACE(ETHERTYPE_PPPOED)
+SED_REPLACE(ETHERTYPE_PPPOES)
+SED_REPLACE(ETHERTYPE_EAPOL)
+SED_REPLACE(ETHERTYPE_RSN_PREAUTH)
+SED_REPLACE(ETHERTYPE_TRILL)
+SED_REPLACE(ETHERTYPE_FCOE)
+SED_REPLACE(ETHERTYPE_MAX)
diff --git a/usr/src/lib/libdtrace/common/vnd.d b/usr/src/lib/libdtrace/common/vnd.d
new file mode 100644
index 0000000000..356c412150
--- /dev/null
+++ b/usr/src/lib/libdtrace/common/vnd.d
@@ -0,0 +1,28 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+
+#pragma D depends_on module vnd
+#pragma D depends_on provider vnd
+#pragma D depends_on library ip.d
+#pragma D depends_on library mac.d
+
+#pragma D binding "1.6.3" translator
+translator ifinfo_t < vnd_str_t *vsp > {
+ if_name = vsp != NULL ? stringof(vsp->vns_dev->vdd_lname) : "<null>";
+ if_local = 0;
+ if_ipstack = vsp != NULL ? vsp->vns_nsd->vpnd_nsid : 0;
+ if_addr = (uintptr_t)vsp;
+};
diff --git a/usr/src/lib/libdwarf/Makefile b/usr/src/lib/libdwarf/Makefile
new file mode 100644
index 0000000000..6b7ff6244b
--- /dev/null
+++ b/usr/src/lib/libdwarf/Makefile
@@ -0,0 +1,40 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint install_h: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libdwarf/Makefile.com b/usr/src/lib/libdwarf/Makefile.com
new file mode 100644
index 0000000000..c737366af9
--- /dev/null
+++ b/usr/src/lib/libdwarf/Makefile.com
@@ -0,0 +1,92 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY= libdwarf.a
+VERS= .1
+
+OBJECTS=dwarf_abbrev.o \
+ dwarf_addr_finder.o \
+ dwarf_alloc.o \
+ dwarf_arange.o \
+ dwarf_die_deliv.o \
+ dwarf_elf_access.o \
+ dwarf_error.o \
+ dwarf_form.o \
+ dwarf_frame.o \
+ dwarf_frame2.o \
+ dwarf_frame3.o \
+ dwarf_funcs.o \
+ dwarf_global.o \
+ dwarf_harmless.o \
+ dwarf_init_finish.o \
+ dwarf_leb.o \
+ dwarf_line.o \
+ dwarf_line2.o \
+ dwarf_loc.o \
+ dwarf_macro.o \
+ dwarf_names.o \
+ dwarf_original_elf_init.o \
+ dwarf_print_lines.o \
+ dwarf_pubtypes.o \
+ dwarf_query.o \
+ dwarf_ranges.o \
+ dwarf_sort_line.o \
+ dwarf_string.o \
+ dwarf_stubs.o \
+ dwarf_types.o \
+ dwarf_util.o \
+ dwarf_vars.o \
+ dwarf_weaks.o \
+ malloc_check.o \
+ pro_alloc.o \
+ pro_arange.o \
+ pro_die.o \
+ pro_encode_nm.o \
+ pro_error.o \
+ pro_expr.o \
+ pro_finish.o \
+ pro_forms.o \
+ pro_frame.o \
+ pro_funcs.o \
+ pro_init.o \
+ pro_line.o \
+ pro_macinfo.o \
+ pro_pubnames.o \
+ pro_reloc.o \
+ pro_reloc_stream.o \
+ pro_reloc_symbolic.o \
+ pro_section.o \
+ pro_types.o \
+ pro_vars.o \
+ pro_weaks.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+LIBS = $(DYNLIB)
+LDLIBS += -lelf -lc
+
+SRCDIR = ../common
+CPPFLAGS += -I$(SRCDIR) -DELF_TARGET_ALL=1
+CERRWARN += -_gcc=-Wno-unused
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libdwarf/THIRDPARTYLICENSE b/usr/src/lib/libdwarf/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..b9320c2d56
--- /dev/null
+++ b/usr/src/lib/libdwarf/THIRDPARTYLICENSE
@@ -0,0 +1,30 @@
+ Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
diff --git a/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip b/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..73abaac973
--- /dev/null
+++ b/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+LIBDWARF LIBRARY THAT SUPPORTS THE DWARF OPEN SOURCE STANDARD
diff --git a/usr/src/lib/libdwarf/amd64/Makefile b/usr/src/lib/libdwarf/amd64/Makefile
new file mode 100644
index 0000000000..15a899f96f
--- /dev/null
+++ b/usr/src/lib/libdwarf/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h b/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h
new file mode 100644
index 0000000000..0eda6d1c44
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h
@@ -0,0 +1,55 @@
+/*
+ dwarf_addr_finder.h
+ $Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/include/cmplrs/RCS/dwarf_addr_finder.h,v $
+ $Date: 2002/06/11 17:49:06 $
+
+ Defines user interface.
+
+*/
+
+/* return codes for functions
+*/
+#define DW_DLV_NO_ENTRY -1
+#define DW_DLV_OK 0
+#define DW_DLV_ERROR 1
+
+
+/* the following are the 'section' number passed to the called-back
+ function.
+ The called-back application must translate this to the
+ appropriate elf section number/pointer.
+
+ Putting this burden on the application avoids having to store
+ the numbers in the Dwarf_Debug structure (thereby saving space
+ for most consumers).
+*/
+#define DW_SECTION_INFO 0
+#define DW_SECTION_FRAME 1
+#define DW_SECTION_ARANGES 2
+#define DW_SECTION_LINE 3
+#define DW_SECTION_LOC 4 /* .debug_loc */
+
+/* section is one of the above codes: it specifies a section.
+ secoff is the offset in the dwarf section.
+ existingAddr is the value at the specified offset (so the
+ called back routine can sanity check the proceedings).
+ It's up to the caller to know the size of an address (4 or 8)
+ and update the right number of bytes.
+*/
+typedef int (*Dwarf_addr_callback_func) (int /*section*/,
+ Dwarf_Off /*secoff*/, Dwarf_Addr /*existingAddr*/);
+
+/* call this to do the work: it calls back thru cb_func
+ once per each address to be modified.
+ Once this returns you are done.
+ Returns DW_DLV_OK if finished ok.
+ Returns DW_DLV_ERROR if there was some kind of error, in which
+ the dwarf error number was passed back thu the dwerr ptr.
+ Returns DW_DLV_NO_ENTRY if there are no relevant dwarf sections,
+ so there were no addresses to be modified (and none
+ called back).
+*/
+int _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,
+ Dwarf_addr_callback_func cb_func,
+ int *dwerr);
+
diff --git a/usr/src/lib/libdwarf/common/config.h b/usr/src/lib/libdwarf/common/config.h
new file mode 100644
index 0000000000..42b286cfda
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/config.h
@@ -0,0 +1,143 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define 1 if want to allow producer to build with 32/64bit section offsets
+ per dwarf3 */
+#define HAVE_DWARF2_99_EXTENSION 1
+
+/* Define to 1 if the elf64_getehdr function is in libelf.a. */
+#define HAVE_ELF64_GETEHDR 1
+
+/* Define to 1 if the elf64_getshdr function is in libelf.a. */
+#define HAVE_ELF64_GETSHDR 1
+
+/* Define 1 if Elf64_Rela defined. */
+#define HAVE_ELF64_RELA 1
+
+/* Define 1 if Elf64_Sym defined. */
+#define HAVE_ELF64_SYM 1
+
+/* Define to 1 if you have the <elfaccess.h> header file. */
+/* #undef HAVE_ELFACCESS_H */
+
+/* Define to 1 if you have the <elf.h> header file. */
+#define HAVE_ELF_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <libelf.h> header file. */
+#define HAVE_LIBELF_H 1
+
+/* Define to 1 if you have the <libelf/libelf.h> header file. */
+/* #undef HAVE_LIBELF_LIBELF_H */
+
+/* Define 1 if off64 is defined via libelf with GNU_SOURCE. */
+#define HAVE_LIBELF_OFF64_OK 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define 1 if need nonstandard printf format for 64bit */
+/* #undef HAVE_NONSTANDARD_PRINTF_64_FORMAT */
+
+/* Define 1 to default to old DW_FRAME_CFA_COL */
+/* #undef HAVE_OLD_FRAME_CFA_COL */
+
+/* Define 1 if plain libelf builds. */
+#define HAVE_RAW_LIBELF_OK 1
+
+/* Define 1 if R_IA_64_DIR32LSB is defined (might be enum value). */
+/* #undef HAVE_R_IA_64_DIR32LSB */
+
+/* Define 1 if want producer to build with IRIX offset sizes */
+/* #undef HAVE_SGI_IRIX_OFFSETS */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define 1 if want producer to build with only 32bit section offsets */
+/* #undef HAVE_STRICT_DWARF2_32BIT_OFFSET */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/ia64/elf.h> header file. */
+/* #undef HAVE_SYS_IA64_ELF_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define 1 if want to allow Windows full path detection */
+/* #undef HAVE_WINDOWS_PATH */
+
+/* See if __uint32_t is predefined in the compiler. */
+/* #undef HAVE___UINT32_T */
+
+/* Define 1 if __uint32_t is in sgidefs.h. */
+/* #undef HAVE___UINT32_T_IN_SGIDEFS_H */
+
+/* Define 1 if sys/types.h defines __uint32_t. */
+/* #undef HAVE___UINT32_T_IN_SYS_TYPES_H */
+
+/* See if __uint64_t is predefined in the compiler. */
+/* #undef HAVE___UINT64_T */
+
+/* Define 1 if is in sgidefs.h. */
+/* #undef HAVE___UINT64_T_IN_SGIDEFS_H */
+
+/* Define 1 if sys/types.h defines __uint64_t. */
+/* #undef HAVE___UINT64_T_IN_SYS_TYPES_H */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# if defined(__sparc)
+# define WORDS_BIGENDIAN 1
+# else
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf.h b/usr/src/lib/libdwarf/common/dwarf.h
new file mode 100644
index 0000000000..b064c4d86b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf.h
@@ -0,0 +1,1078 @@
+/*
+ Copyright (C) 2000,2001,2003,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2007-2010 David Anderson. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#ifndef __DWARF_H
+#define __DWARF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ dwarf.h DWARF debugging information values
+ $Revision: 1.41 $ $Date: 2006/04/17 00:09:56 $
+
+ The comment "DWARF3" appears where there are
+ new entries from DWARF3 as of 2004, "DWARF3f"
+ where there are new entries as of the November 2005
+ public review document and other comments apply
+ where extension entries appear.
+
+ Extensions part of DWARF4 are marked DWARF4.
+
+ A few extension names have omitted the 'vendor id'
+ (See chapter 7, "Vendor Extensibility"). Please
+ always use a 'vendor id' string in extension names.
+
+ Vendors should use a vendor string in names and
+ whereever possible avoid duplicating values used by
+ other vendor extensions
+
+*/
+
+
+#define DW_TAG_array_type 0x01
+#define DW_TAG_class_type 0x02
+#define DW_TAG_entry_point 0x03
+#define DW_TAG_enumeration_type 0x04
+#define DW_TAG_formal_parameter 0x05
+#define DW_TAG_imported_declaration 0x08
+#define DW_TAG_label 0x0a
+#define DW_TAG_lexical_block 0x0b
+#define DW_TAG_member 0x0d
+#define DW_TAG_pointer_type 0x0f
+#define DW_TAG_reference_type 0x10
+#define DW_TAG_compile_unit 0x11
+#define DW_TAG_string_type 0x12
+#define DW_TAG_structure_type 0x13
+#define DW_TAG_subroutine_type 0x15
+#define DW_TAG_typedef 0x16
+#define DW_TAG_union_type 0x17
+#define DW_TAG_unspecified_parameters 0x18
+#define DW_TAG_variant 0x19
+#define DW_TAG_common_block 0x1a
+#define DW_TAG_common_inclusion 0x1b
+#define DW_TAG_inheritance 0x1c
+#define DW_TAG_inlined_subroutine 0x1d
+#define DW_TAG_module 0x1e
+#define DW_TAG_ptr_to_member_type 0x1f
+#define DW_TAG_set_type 0x20
+#define DW_TAG_subrange_type 0x21
+#define DW_TAG_with_stmt 0x22
+#define DW_TAG_access_declaration 0x23
+#define DW_TAG_base_type 0x24
+#define DW_TAG_catch_block 0x25
+#define DW_TAG_const_type 0x26
+#define DW_TAG_constant 0x27
+#define DW_TAG_enumerator 0x28
+#define DW_TAG_file_type 0x29
+#define DW_TAG_friend 0x2a
+#define DW_TAG_namelist 0x2b
+ /* Early releases of this header had the following
+ misspelled with a trailing 's' */
+#define DW_TAG_namelist_item 0x2c /* DWARF3/2 spelling */
+#define DW_TAG_namelist_items 0x2c /* SGI misspelling/typo */
+#define DW_TAG_packed_type 0x2d
+#define DW_TAG_subprogram 0x2e
+ /* The DWARF2 document had two spellings of the following
+ two TAGs, DWARF3 specifies the longer spelling. */
+#define DW_TAG_template_type_parameter 0x2f /* DWARF3/2 spelling*/
+#define DW_TAG_template_type_param 0x2f /* DWARF2 spelling*/
+#define DW_TAG_template_value_parameter 0x30 /* DWARF3/2 spelling*/
+#define DW_TAG_template_value_param 0x30 /* DWARF2 spelling*/
+#define DW_TAG_thrown_type 0x31
+#define DW_TAG_try_block 0x32
+#define DW_TAG_variant_part 0x33
+#define DW_TAG_variable 0x34
+#define DW_TAG_volatile_type 0x35
+#define DW_TAG_dwarf_procedure 0x36 /* DWARF3 */
+#define DW_TAG_restrict_type 0x37 /* DWARF3 */
+#define DW_TAG_interface_type 0x38 /* DWARF3 */
+#define DW_TAG_namespace 0x39 /* DWARF3 */
+#define DW_TAG_imported_module 0x3a /* DWARF3 */
+#define DW_TAG_unspecified_type 0x3b /* DWARF3 */
+#define DW_TAG_partial_unit 0x3c /* DWARF3 */
+#define DW_TAG_imported_unit 0x3d /* DWARF3 */
+ /* Do not use DW_TAG_mutable_type */
+#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */
+#define DW_TAG_condition 0x3f /* DWARF3f */
+#define DW_TAG_shared_type 0x40 /* DWARF3f */
+#define DW_TAG_type_unit 0x41 /* DWARF4 */
+#define DW_TAG_rvalue_reference_type 0x42 /* DWARF4 */
+#define DW_TAG_template_alias 0x43 /* DWARF4 */
+#define DW_TAG_lo_user 0x4080
+
+#define DW_TAG_MIPS_loop 0x4081
+
+/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz */
+#define DW_TAG_HP_array_descriptor 0x4090 /* HP */
+
+/* GNU extensions. The first 3 missing the GNU_. */
+#define DW_TAG_format_label 0x4101 /* GNU. Fortran. */
+#define DW_TAG_function_template 0x4102 /* GNU. For C++ */
+#define DW_TAG_class_template 0x4103 /* GNU. For C++ */
+#define DW_TAG_GNU_BINCL 0x4104 /* GNU */
+#define DW_TAG_GNU_EINCL 0x4105 /* GNU */
+
+
+/* GNU extension. http://gcc.gnu.org/wiki/TemplateParmsDwarf */
+#define DW_TAG_GNU_template_template_parameter 0x4106 /* GNU */
+#define DW_TAG_GNU_template_template_param 0x4106 /* GNU */
+#define DW_TAG_GNU_template_parameter_pack 0x4107 /* GNU */
+#define DW_TAG_GNU_formal_parameter_pack 0x4108 /* GNU */
+
+/* ALTIUM extensions */
+ /* DSP-C/Starcore __circ qualifier */
+#define DW_TAG_ALTIUM_circ_type 0x5101 /* ALTIUM */
+ /* Starcore __mwa_circ qualifier */
+#define DW_TAG_ALTIUM_mwa_circ_type 0x5102 /* ALTIUM */
+ /* Starcore __rev_carry qualifier */
+#define DW_TAG_ALTIUM_rev_carry_type 0x5103 /* ALTIUM */
+ /* M16 __rom qualifier */
+#define DW_TAG_ALTIUM_rom 0x5111 /* ALTIUM */
+
+/* The following 3 are extensions to support UPC */
+#define DW_TAG_upc_shared_type 0x8765 /* UPC */
+#define DW_TAG_upc_strict_type 0x8766 /* UPC */
+#define DW_TAG_upc_relaxed_type 0x8767 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_TAG_PGI_kanji_type 0xa000 /* PGI */
+#define DW_TAG_PGI_interface_block 0xa020 /* PGI */
+/* The following are SUN extensions */
+#define DW_TAG_SUN_function_template 0x4201 /* SUN */
+#define DW_TAG_SUN_class_template 0x4202 /* SUN */
+#define DW_TAG_SUN_struct_template 0x4203 /* SUN */
+#define DW_TAG_SUN_union_template 0x4204 /* SUN */
+#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */
+#define DW_TAG_SUN_codeflags 0x4206 /* SUN */
+#define DW_TAG_SUN_memop_info 0x4207 /* SUN */
+#define DW_TAG_SUN_omp_child_func 0x4208 /* SUN */
+#define DW_TAG_SUN_rtti_descriptor 0x4209 /* SUN */
+#define DW_TAG_SUN_dtor_info 0x420a /* SUN */
+#define DW_TAG_SUN_dtor 0x420b /* SUN */
+#define DW_TAG_SUN_f90_interface 0x420c /* SUN */
+#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */
+#define DW_TAG_SUN_hi 0x42ff /* SUN */
+
+
+#define DW_TAG_hi_user 0xffff
+
+#define DW_children_no 0
+#define DW_children_yes 1
+
+
+
+#define DW_FORM_addr 0x01
+#define DW_FORM_block2 0x03
+#define DW_FORM_block4 0x04
+#define DW_FORM_data2 0x05
+#define DW_FORM_data4 0x06
+#define DW_FORM_data8 0x07
+#define DW_FORM_string 0x08
+#define DW_FORM_block 0x09
+#define DW_FORM_block1 0x0a
+#define DW_FORM_data1 0x0b
+#define DW_FORM_flag 0x0c
+#define DW_FORM_sdata 0x0d
+#define DW_FORM_strp 0x0e
+#define DW_FORM_udata 0x0f
+#define DW_FORM_ref_addr 0x10
+#define DW_FORM_ref1 0x11
+#define DW_FORM_ref2 0x12
+#define DW_FORM_ref4 0x13
+#define DW_FORM_ref8 0x14
+#define DW_FORM_ref_udata 0x15
+#define DW_FORM_indirect 0x16
+#define DW_FORM_sec_offset 0x17 /* DWARF4 */
+#define DW_FORM_exprloc 0x18 /* DWARF4 */
+#define DW_FORM_flag_present 0x19 /* DWARF4 */
+/* 0x1a thru 0x1f were left unused accidentally. Reserved for future use. */
+#define DW_FORM_ref_sig8 0x20 /* DWARF4 */
+
+#define DW_AT_sibling 0x01
+#define DW_AT_location 0x02
+#define DW_AT_name 0x03
+#define DW_AT_ordering 0x09
+#define DW_AT_subscr_data 0x0a
+#define DW_AT_byte_size 0x0b
+#define DW_AT_bit_offset 0x0c
+#define DW_AT_bit_size 0x0d
+#define DW_AT_element_list 0x0f
+#define DW_AT_stmt_list 0x10
+#define DW_AT_low_pc 0x11
+#define DW_AT_high_pc 0x12
+#define DW_AT_language 0x13
+#define DW_AT_member 0x14
+#define DW_AT_discr 0x15
+#define DW_AT_discr_value 0x16
+#define DW_AT_visibility 0x17
+#define DW_AT_import 0x18
+#define DW_AT_string_length 0x19
+#define DW_AT_common_reference 0x1a
+#define DW_AT_comp_dir 0x1b
+#define DW_AT_const_value 0x1c
+#define DW_AT_containing_type 0x1d
+#define DW_AT_default_value 0x1e
+#define DW_AT_inline 0x20
+#define DW_AT_is_optional 0x21
+#define DW_AT_lower_bound 0x22
+#define DW_AT_producer 0x25
+#define DW_AT_prototyped 0x27
+#define DW_AT_return_addr 0x2a
+#define DW_AT_start_scope 0x2c
+#define DW_AT_bit_stride 0x2e /* DWARF3 name */
+#define DW_AT_stride_size 0x2e /* DWARF2 name */
+#define DW_AT_upper_bound 0x2f
+#define DW_AT_abstract_origin 0x31
+#define DW_AT_accessibility 0x32
+#define DW_AT_address_class 0x33
+#define DW_AT_artificial 0x34
+#define DW_AT_base_types 0x35
+#define DW_AT_calling_convention 0x36
+#define DW_AT_count 0x37
+#define DW_AT_data_member_location 0x38
+#define DW_AT_decl_column 0x39
+#define DW_AT_decl_file 0x3a
+#define DW_AT_decl_line 0x3b
+#define DW_AT_declaration 0x3c
+#define DW_AT_discr_list 0x3d
+#define DW_AT_encoding 0x3e
+#define DW_AT_external 0x3f
+#define DW_AT_frame_base 0x40
+#define DW_AT_friend 0x41
+#define DW_AT_identifier_case 0x42
+#define DW_AT_macro_info 0x43
+#define DW_AT_namelist_item 0x44
+#define DW_AT_priority 0x45
+#define DW_AT_segment 0x46
+#define DW_AT_specification 0x47
+#define DW_AT_static_link 0x48
+#define DW_AT_type 0x49
+#define DW_AT_use_location 0x4a
+#define DW_AT_variable_parameter 0x4b
+#define DW_AT_virtuality 0x4c
+#define DW_AT_vtable_elem_location 0x4d
+#define DW_AT_allocated 0x4e /* DWARF3 */
+#define DW_AT_associated 0x4f /* DWARF3 */
+#define DW_AT_data_location 0x50 /* DWARF3 */
+#define DW_AT_byte_stride 0x51 /* DWARF3f */
+#define DW_AT_stride 0x51 /* DWARF3 (do not use) */
+#define DW_AT_entry_pc 0x52 /* DWARF3 */
+#define DW_AT_use_UTF8 0x53 /* DWARF3 */
+#define DW_AT_extension 0x54 /* DWARF3 */
+#define DW_AT_ranges 0x55 /* DWARF3 */
+#define DW_AT_trampoline 0x56 /* DWARF3 */
+#define DW_AT_call_column 0x57 /* DWARF3 */
+#define DW_AT_call_file 0x58 /* DWARF3 */
+#define DW_AT_call_line 0x59 /* DWARF3 */
+#define DW_AT_description 0x5a /* DWARF3 */
+#define DW_AT_binary_scale 0x5b /* DWARF3f */
+#define DW_AT_decimal_scale 0x5c /* DWARF3f */
+#define DW_AT_small 0x5d /* DWARF3f */
+#define DW_AT_decimal_sign 0x5e /* DWARF3f */
+#define DW_AT_digit_count 0x5f /* DWARF3f */
+#define DW_AT_picture_string 0x60 /* DWARF3f */
+#define DW_AT_mutable 0x61 /* DWARF3f */
+#define DW_AT_threads_scaled 0x62 /* DWARF3f */
+#define DW_AT_explicit 0x63 /* DWARF3f */
+#define DW_AT_object_pointer 0x64 /* DWARF3f */
+#define DW_AT_endianity 0x65 /* DWARF3f */
+#define DW_AT_elemental 0x66 /* DWARF3f */
+#define DW_AT_pure 0x67 /* DWARF3f */
+#define DW_AT_recursive 0x68 /* DWARF3f */
+#define DW_AT_signature 0x69 /* DWARF4 */
+#define DW_AT_main_subprogram 0x6a /* DWARF4 */
+#define DW_AT_data_bit_offset 0x6b /* DWARF4 */
+#define DW_AT_const_expr 0x6c /* DWARF4 */
+#define DW_AT_enum_class 0x6d /* DWARF4 */
+#define DW_AT_linkage_name 0x6e /* DWARF4 */
+
+/* In extensions, we attempt to include the vendor extension
+ in the name even when the vendor leaves it out. */
+
+/* HP extensions. */
+#define DW_AT_HP_block_index 0x2000 /* HP */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_AT_lo_user 0x2000
+
+#define DW_AT_MIPS_fde 0x2001 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_begin 0x2002 /* MIPS/SGI */
+#define DW_AT_MIPS_tail_loop_begin 0x2003 /* MIPS/SGI */
+#define DW_AT_MIPS_epilog_begin 0x2004 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_unroll_factor 0x2005 /* MIPS/SGI */
+#define DW_AT_MIPS_software_pipeline_depth 0x2006 /* MIPS/SGI */
+#define DW_AT_MIPS_linkage_name 0x2007 /* MIPS/SGI, GNU, and others.*/
+#define DW_AT_MIPS_stride 0x2008 /* MIPS/SGI */
+#define DW_AT_MIPS_abstract_name 0x2009 /* MIPS/SGI */
+#define DW_AT_MIPS_clone_origin 0x200a /* MIPS/SGI */
+#define DW_AT_MIPS_has_inlines 0x200b /* MIPS/SGI */
+#define DW_AT_MIPS_stride_byte 0x200c /* MIPS/SGI */
+#define DW_AT_MIPS_stride_elem 0x200d /* MIPS/SGI */
+#define DW_AT_MIPS_ptr_dopetype 0x200e /* MIPS/SGI */
+#define DW_AT_MIPS_allocatable_dopetype 0x200f /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_size 0x2011 /* MIPS/SGI */
+
+/* HP extensions. */
+#define DW_AT_HP_unmodifiable 0x2001 /* conflict: MIPS */
+#define DW_AT_HP_actuals_stmt_list 0x2010 /* conflict: MIPS */
+#define DW_AT_HP_proc_per_section 0x2011 /* conflict: MIPS */
+#define DW_AT_HP_raw_data_ptr 0x2012 /* HP */
+#define DW_AT_HP_pass_by_reference 0x2013 /* HP */
+#define DW_AT_HP_opt_level 0x2014 /* HP */
+#define DW_AT_HP_prof_version_id 0x2015 /* HP */
+#define DW_AT_HP_opt_flags 0x2016 /* HP */
+#define DW_AT_HP_cold_region_low_pc 0x2017 /* HP */
+#define DW_AT_HP_cold_region_high_pc 0x2018 /* HP */
+#define DW_AT_HP_all_variables_modifiable 0x2019 /* HP */
+#define DW_AT_HP_linkage_name 0x201a /* HP */
+#define DW_AT_HP_prof_flags 0x201b /* HP */
+
+#define DW_AT_CPQ_discontig_ranges 0x2001 /* COMPAQ/HP */
+#define DW_AT_CPQ_semantic_events 0x2002 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_var 0x2003 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_rtn 0x2004 /* COMPAQ/HP */
+#define DW_AT_CPQ_prologue_length 0x2005 /* COMPAQ/HP */
+
+#define DW_AT_INTEL_other_endian 0x2026 /* Intel, 1 if byte swapped. */
+
+/* GNU extensions. */
+#define DW_AT_sf_names 0x2101 /* GNU */
+#define DW_AT_src_info 0x2102 /* GNU */
+#define DW_AT_mac_info 0x2103 /* GNU */
+#define DW_AT_src_coords 0x2104 /* GNU */
+#define DW_AT_body_begin 0x2105 /* GNU */
+#define DW_AT_body_end 0x2106 /* GNU */
+#define DW_AT_GNU_vector 0x2107 /* GNU */
+#define DW_AT_GNU_template_name 0x2108 /* GNU */
+
+/* ALTIUM extension: ALTIUM Compliant location lists (flag) */
+#define DW_AT_ALTIUM_loclist 0x2300 /* ALTIUM */
+
+/* Sun extensions */
+#define DW_AT_SUN_template 0x2201 /* SUN */
+#define DW_AT_VMS_rtnbeg_pd_address 0x2201 /* VMS */
+#define DW_AT_SUN_alignment 0x2202 /* SUN */
+#define DW_AT_SUN_vtable 0x2203 /* SUN */
+#define DW_AT_SUN_count_guarantee 0x2204 /* SUN */
+#define DW_AT_SUN_command_line 0x2205 /* SUN */
+#define DW_AT_SUN_vbase 0x2206 /* SUN */
+#define DW_AT_SUN_compile_options 0x2207 /* SUN */
+#define DW_AT_SUN_language 0x2208 /* SUN */
+#define DW_AT_SUN_browser_file 0x2209 /* SUN */
+#define DW_AT_SUN_vtable_abi 0x2210 /* SUN */
+#define DW_AT_SUN_func_offsets 0x2211 /* SUN */
+#define DW_AT_SUN_cf_kind 0x2212 /* SUN */
+#define DW_AT_SUN_vtable_index 0x2213 /* SUN */
+#define DW_AT_SUN_omp_tpriv_addr 0x2214 /* SUN */
+#define DW_AT_SUN_omp_child_func 0x2215 /* SUN */
+#define DW_AT_SUN_func_offset 0x2216 /* SUN */
+#define DW_AT_SUN_memop_type_ref 0x2217 /* SUN */
+#define DW_AT_SUN_profile_id 0x2218 /* SUN */
+#define DW_AT_SUN_memop_signature 0x2219 /* SUN */
+#define DW_AT_SUN_obj_dir 0x2220 /* SUN */
+#define DW_AT_SUN_obj_file 0x2221 /* SUN */
+#define DW_AT_SUN_original_name 0x2222 /* SUN */
+#define DW_AT_SUN_hwcprof_signature 0x2223 /* SUN */
+#define DW_AT_SUN_amd64_parmdump 0x2224 /* SUN */
+#define DW_AT_SUN_part_link_name 0x2225 /* SUN */
+#define DW_AT_SUN_link_name 0x2226 /* SUN */
+#define DW_AT_SUN_pass_with_const 0x2227 /* SUN */
+#define DW_AT_SUN_return_with_const 0x2228 /* SUN */
+#define DW_AT_SUN_import_by_name 0x2229 /* SUN */
+#define DW_AT_SUN_f90_pointer 0x222a /* SUN */
+#define DW_AT_SUN_pass_by_ref 0x222b /* SUN */
+#define DW_AT_SUN_f90_allocatable 0x222c /* SUN */
+#define DW_AT_SUN_f90_assumed_shape_array 0x222d /* SUN */
+#define DW_AT_SUN_c_vla 0x222e /* SUN */
+#define DW_AT_SUN_return_value_ptr 0x2230 /* SUN */
+#define DW_AT_SUN_dtor_start 0x2231 /* SUN */
+#define DW_AT_SUN_dtor_length 0x2232 /* SUN */
+#define DW_AT_SUN_dtor_state_initial 0x2233 /* SUN */
+#define DW_AT_SUN_dtor_state_final 0x2234 /* SUN */
+#define DW_AT_SUN_dtor_state_deltas 0x2235 /* SUN */
+#define DW_AT_SUN_import_by_lname 0x2236 /* SUN */
+#define DW_AT_SUN_f90_use_only 0x2237 /* SUN */
+#define DW_AT_SUN_namelist_spec 0x2238 /* SUN */
+#define DW_AT_SUN_is_omp_child_func 0x2239 /* SUN */
+#define DW_AT_SUN_fortran_main_alias 0x223a /* SUN */
+#define DW_AT_SUN_fortran_based 0x223b /* SUN */
+
+/* UPC extension */
+#define DW_AT_upc_threads_scaled 0x3210 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_AT_PGI_lbase 0x3a00 /* PGI. Block, constant, reference. This attribute is an ASTPLAB extension used to describe the array local base. */
+#define DW_AT_PGI_soffset 0x3a01 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the section offset, or the offset to the first element in the dimension. */
+#define DW_AT_PGI_lstride 0x3a02 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the linear stride or the distance between elements in the dimension. */
+
+/* Apple Extensions for closures */
+#define DW_AT_APPLE_closure 0x3fe4 /* Apple */
+/* Apple Extensions for Objective-C runtime info */
+#define DW_AT_APPLE_major_runtime_vers 0x3fe5 /* Apple */
+#define DW_AT_APPLE_runtime_class 0x3fe6 /* Apple */
+
+
+#define DW_AT_hi_user 0x3fff
+
+#define DW_OP_addr 0x03
+#define DW_OP_deref 0x06
+#define DW_OP_const1u 0x08
+#define DW_OP_const1s 0x09
+#define DW_OP_const2u 0x0a
+#define DW_OP_const2s 0x0b
+#define DW_OP_const4u 0x0c
+#define DW_OP_const4s 0x0d
+#define DW_OP_const8u 0x0e
+#define DW_OP_const8s 0x0f
+#define DW_OP_constu 0x10
+#define DW_OP_consts 0x11
+#define DW_OP_dup 0x12
+#define DW_OP_drop 0x13
+#define DW_OP_over 0x14
+#define DW_OP_pick 0x15
+#define DW_OP_swap 0x16
+#define DW_OP_rot 0x17
+#define DW_OP_xderef 0x18
+#define DW_OP_abs 0x19
+#define DW_OP_and 0x1a
+#define DW_OP_div 0x1b
+#define DW_OP_minus 0x1c
+#define DW_OP_mod 0x1d
+#define DW_OP_mul 0x1e
+#define DW_OP_neg 0x1f
+#define DW_OP_not 0x20
+#define DW_OP_or 0x21
+#define DW_OP_plus 0x22
+#define DW_OP_plus_uconst 0x23
+#define DW_OP_shl 0x24
+#define DW_OP_shr 0x25
+#define DW_OP_shra 0x26
+#define DW_OP_xor 0x27
+#define DW_OP_bra 0x28
+#define DW_OP_eq 0x29
+#define DW_OP_ge 0x2a
+#define DW_OP_gt 0x2b
+#define DW_OP_le 0x2c
+#define DW_OP_lt 0x2d
+#define DW_OP_ne 0x2e
+#define DW_OP_skip 0x2f
+#define DW_OP_lit0 0x30
+#define DW_OP_lit1 0x31
+#define DW_OP_lit2 0x32
+#define DW_OP_lit3 0x33
+#define DW_OP_lit4 0x34
+#define DW_OP_lit5 0x35
+#define DW_OP_lit6 0x36
+#define DW_OP_lit7 0x37
+#define DW_OP_lit8 0x38
+#define DW_OP_lit9 0x39
+#define DW_OP_lit10 0x3a
+#define DW_OP_lit11 0x3b
+#define DW_OP_lit12 0x3c
+#define DW_OP_lit13 0x3d
+#define DW_OP_lit14 0x3e
+#define DW_OP_lit15 0x3f
+#define DW_OP_lit16 0x40
+#define DW_OP_lit17 0x41
+#define DW_OP_lit18 0x42
+#define DW_OP_lit19 0x43
+#define DW_OP_lit20 0x44
+#define DW_OP_lit21 0x45
+#define DW_OP_lit22 0x46
+#define DW_OP_lit23 0x47
+#define DW_OP_lit24 0x48
+#define DW_OP_lit25 0x49
+#define DW_OP_lit26 0x4a
+#define DW_OP_lit27 0x4b
+#define DW_OP_lit28 0x4c
+#define DW_OP_lit29 0x4d
+#define DW_OP_lit30 0x4e
+#define DW_OP_lit31 0x4f
+#define DW_OP_reg0 0x50
+#define DW_OP_reg1 0x51
+#define DW_OP_reg2 0x52
+#define DW_OP_reg3 0x53
+#define DW_OP_reg4 0x54
+#define DW_OP_reg5 0x55
+#define DW_OP_reg6 0x56
+#define DW_OP_reg7 0x57
+#define DW_OP_reg8 0x58
+#define DW_OP_reg9 0x59
+#define DW_OP_reg10 0x5a
+#define DW_OP_reg11 0x5b
+#define DW_OP_reg12 0x5c
+#define DW_OP_reg13 0x5d
+#define DW_OP_reg14 0x5e
+#define DW_OP_reg15 0x5f
+#define DW_OP_reg16 0x60
+#define DW_OP_reg17 0x61
+#define DW_OP_reg18 0x62
+#define DW_OP_reg19 0x63
+#define DW_OP_reg20 0x64
+#define DW_OP_reg21 0x65
+#define DW_OP_reg22 0x66
+#define DW_OP_reg23 0x67
+#define DW_OP_reg24 0x68
+#define DW_OP_reg25 0x69
+#define DW_OP_reg26 0x6a
+#define DW_OP_reg27 0x6b
+#define DW_OP_reg28 0x6c
+#define DW_OP_reg29 0x6d
+#define DW_OP_reg30 0x6e
+#define DW_OP_reg31 0x6f
+#define DW_OP_breg0 0x70
+#define DW_OP_breg1 0x71
+#define DW_OP_breg2 0x72
+#define DW_OP_breg3 0x73
+#define DW_OP_breg4 0x74
+#define DW_OP_breg5 0x75
+#define DW_OP_breg6 0x76
+#define DW_OP_breg7 0x77
+#define DW_OP_breg8 0x78
+#define DW_OP_breg9 0x79
+#define DW_OP_breg10 0x7a
+#define DW_OP_breg11 0x7b
+#define DW_OP_breg12 0x7c
+#define DW_OP_breg13 0x7d
+#define DW_OP_breg14 0x7e
+#define DW_OP_breg15 0x7f
+#define DW_OP_breg16 0x80
+#define DW_OP_breg17 0x81
+#define DW_OP_breg18 0x82
+#define DW_OP_breg19 0x83
+#define DW_OP_breg20 0x84
+#define DW_OP_breg21 0x85
+#define DW_OP_breg22 0x86
+#define DW_OP_breg23 0x87
+#define DW_OP_breg24 0x88
+#define DW_OP_breg25 0x89
+#define DW_OP_breg26 0x8a
+#define DW_OP_breg27 0x8b
+#define DW_OP_breg28 0x8c
+#define DW_OP_breg29 0x8d
+#define DW_OP_breg30 0x8e
+#define DW_OP_breg31 0x8f
+#define DW_OP_regx 0x90
+#define DW_OP_fbreg 0x91
+#define DW_OP_bregx 0x92
+#define DW_OP_piece 0x93
+#define DW_OP_deref_size 0x94
+#define DW_OP_xderef_size 0x95
+#define DW_OP_nop 0x96
+#define DW_OP_push_object_address 0x97 /* DWARF3 */
+#define DW_OP_call2 0x98 /* DWARF3 */
+#define DW_OP_call4 0x99 /* DWARF3 */
+#define DW_OP_call_ref 0x9a /* DWARF3 */
+#define DW_OP_form_tls_address 0x9b /* DWARF3f */
+#define DW_OP_call_frame_cfa 0x9c /* DWARF3f */
+#define DW_OP_bit_piece 0x9d /* DWARF3f */
+#define DW_OP_implicit_value 0x9e /* DWARF4 */
+#define DW_OP_stack_value 0x9f /* DWARF4 */
+
+
+ /* GNU extensions. */
+#define DW_OP_GNU_push_tls_address 0xe0 /* GNU */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_OP_lo_user 0xe0
+
+ /* HP extensions. */
+#define DW_OP_HP_unknown 0xe0 /* HP conflict: GNU */
+#define DW_OP_HP_is_value 0xe1 /* HP */
+#define DW_OP_HP_fltconst4 0xe2 /* HP */
+#define DW_OP_HP_fltconst8 0xe3 /* HP */
+#define DW_OP_HP_mod_range 0xe4 /* HP */
+#define DW_OP_HP_unmod_range 0xe5 /* HP */
+#define DW_OP_HP_tls 0xe6 /* HP */
+
+#define DW_OP_INTEL_bit_piece 0xe8 /* Intel: made obsolete by DW_OP_bit_piece above. */
+
+
+ /* Apple extension. */
+#define DW_OP_APPLE_uninit 0xf0 /* Apple */
+
+#define DW_OP_hi_user 0xff
+
+#define DW_ATE_address 0x1
+#define DW_ATE_boolean 0x2
+#define DW_ATE_complex_float 0x3
+#define DW_ATE_float 0x4
+#define DW_ATE_signed 0x5
+#define DW_ATE_signed_char 0x6
+#define DW_ATE_unsigned 0x7
+#define DW_ATE_unsigned_char 0x8
+#define DW_ATE_imaginary_float 0x9 /* DWARF3 */
+#define DW_ATE_packed_decimal 0xa /* DWARF3f */
+#define DW_ATE_numeric_string 0xb /* DWARF3f */
+#define DW_ATE_edited 0xc /* DWARF3f */
+#define DW_ATE_signed_fixed 0xd /* DWARF3f */
+#define DW_ATE_unsigned_fixed 0xe /* DWARF3f */
+#define DW_ATE_decimal_float 0xf /* DWARF3f */
+
+
+/* ALTIUM extensions. x80, x81 */
+#define DW_ATE_ALTIUM_fract 0x80 /* ALTIUM __fract type */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_ATE_lo_user 0x80
+
+/* Shown here to help dwarfdump build script. */
+#define DW_ATE_ALTIUM_accum 0x81 /* ALTIUM __accum type */
+
+/* HP Floating point extensions. */
+#define DW_ATE_HP_float80 0x80 /* (80 bit). HP */
+
+
+#define DW_ATE_HP_complex_float80 0x81 /* Complex (80 bit). HP */
+#define DW_ATE_HP_float128 0x82 /* (128 bit). HP */
+#define DW_ATE_HP_complex_float128 0x83 /* Complex (128 bit). HP */
+#define DW_ATE_HP_floathpintel 0x84 /* (82 bit IA64). HP */
+#define DW_ATE_HP_imaginary_float80 0x85 /* HP */
+#define DW_ATE_HP_imaginary_float128 0x86 /* HP */
+
+/* Sun extensions */
+#define DW_ATE_SUN_interval_float 0x91
+#define DW_ATE_SUN_imaginary_float 0x92 /* Obsolete: See DW_ATE_imaginary_float */
+
+#define DW_ATE_hi_user 0xff
+
+
+/* Decimal Sign codes. */
+#define DW_DS_unsigned 0x01 /* DWARF3f */
+#define DW_DS_leading_overpunch 0x02 /* DWARF3f */
+#define DW_DS_trailing_overpunch 0x03 /* DWARF3f */
+#define DW_DS_leading_separate 0x04 /* DWARF3f */
+
+#define DW_DS_trailing_separate 0x05 /* DWARF3f */
+
+/* Endian code name. */
+#define DW_END_default 0x00 /* DWARF3f */
+#define DW_END_big 0x01 /* DWARF3f */
+#define DW_END_little 0x02 /* DWARF3f */
+
+#define DW_END_lo_user 0x40 /* DWARF3f */
+#define DW_END_hi_user 0xff /* DWARF3f */
+
+/* For use with DW_TAG_SUN_codeflags
+ * If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then
+ * standard dwarf ATCF entries start at 0x01
+ */
+#define DW_ATCF_lo_user 0x40 /* SUN */
+#define DW_ATCF_SUN_mop_bitfield 0x41 /* SUN */
+#define DW_ATCF_SUN_mop_spill 0x42 /* SUN */
+#define DW_ATCF_SUN_mop_scopy 0x43 /* SUN */
+#define DW_ATCF_SUN_func_start 0x44 /* SUN */
+#define DW_ATCF_SUN_end_ctors 0x45 /* SUN */
+#define DW_ATCF_SUN_branch_target 0x46 /* SUN */
+#define DW_ATCF_SUN_mop_stack_probe 0x47 /* SUN */
+#define DW_ATCF_SUN_func_epilog 0x48 /* SUN */
+#define DW_ATCF_hi_user 0xff /* SUN */
+
+/* Accessibility code name. */
+#define DW_ACCESS_public 0x01
+#define DW_ACCESS_protected 0x02
+#define DW_ACCESS_private 0x03
+
+/* Visibility code name. */
+#define DW_VIS_local 0x01
+#define DW_VIS_exported 0x02
+#define DW_VIS_qualified 0x03
+
+/* Virtuality code name. */
+#define DW_VIRTUALITY_none 0x00
+#define DW_VIRTUALITY_virtual 0x01
+#define DW_VIRTUALITY_pure_virtual 0x02
+
+#define DW_LANG_C89 0x0001
+#define DW_LANG_C 0x0002
+#define DW_LANG_Ada83 0x0003
+#define DW_LANG_C_plus_plus 0x0004
+#define DW_LANG_Cobol74 0x0005
+#define DW_LANG_Cobol85 0x0006
+#define DW_LANG_Fortran77 0x0007
+#define DW_LANG_Fortran90 0x0008
+#define DW_LANG_Pascal83 0x0009
+#define DW_LANG_Modula2 0x000a
+#define DW_LANG_Java 0x000b /* DWARF3 */
+#define DW_LANG_C99 0x000c /* DWARF3 */
+#define DW_LANG_Ada95 0x000d /* DWARF3 */
+#define DW_LANG_Fortran95 0x000e /* DWARF3 */
+#define DW_LANG_PLI 0x000f /* DWARF3 */
+#define DW_LANG_ObjC 0x0010 /* DWARF3f */
+#define DW_LANG_ObjC_plus_plus 0x0011 /* DWARF3f */
+#define DW_LANG_UPC 0x0012 /* DWARF3f */
+#define DW_LANG_D 0x0013 /* DWARF3f */
+#define DW_LANG_Python 0x0014 /* DWARF4 */
+/* The following 2 are not yet formally approved October 2010, but
+ it seems extremely likely they will be approved as the committee
+ chair agrees these should be ok and no one on the committee
+ has objected. */
+#define DW_LANG_OpenCL 0x0015 /* Provisionally DWARF5 */
+#define DW_LANG_Go 0x0016 /* Provisionally DWARF5 */
+#define DW_LANG_lo_user 0x8000
+#define DW_LANG_Mips_Assembler 0x8001 /* MIPS */
+#define DW_LANG_Upc 0x8765 /* UPC, use
+ DW_LANG_UPC instead. */
+/* ALTIUM extension */
+#define DW_LANG_ALTIUM_Assembler 0x9101 /* ALTIUM */
+
+/* Sun extensions */
+#define DW_LANG_SUN_Assembler 0x9001 /* SUN */
+
+#define DW_LANG_hi_user 0xffff
+
+/* Identifier case name. */
+#define DW_ID_case_sensitive 0x00
+#define DW_ID_up_case 0x01
+#define DW_ID_down_case 0x02
+#define DW_ID_case_insensitive 0x03
+
+/* Calling Convention Name. */
+#define DW_CC_normal 0x01
+#define DW_CC_program 0x02
+#define DW_CC_nocall 0x03
+#define DW_CC_lo_user 0x40
+
+/* ALTIUM extensions. */
+/* Function is an interrupt handler, return address on system stack. */
+#define DW_CC_ALTIUM_interrupt 0x65 /* ALTIUM*/
+
+/* Near function model, return address on system stack. */
+#define DW_CC_ALTIUM_near_system_stack 0x66 /*ALTIUM */
+
+/* Near function model, return address on user stack. */
+#define DW_CC_ALTIUM_near_user_stack 0x67 /* ALTIUM */
+
+/* Huge function model, return address on user stack. */
+#define DW_CC_ALTIUM_huge_user_stack 0x68 /* ALTIUM */
+
+
+#define DW_CC_hi_user 0xff
+
+/* Inline Code Name. */
+#define DW_INL_not_inlined 0x00
+#define DW_INL_inlined 0x01
+#define DW_INL_declared_not_inlined 0x02
+#define DW_INL_declared_inlined 0x03
+
+/* Ordering Name. */
+#define DW_ORD_row_major 0x00
+#define DW_ORD_col_major 0x01
+
+/* Discriminant Descriptor Name. */
+#define DW_DSC_label 0x00
+#define DW_DSC_range 0x01
+
+/* Line number standard opcode name. */
+#define DW_LNS_copy 0x01
+#define DW_LNS_advance_pc 0x02
+#define DW_LNS_advance_line 0x03
+#define DW_LNS_set_file 0x04
+#define DW_LNS_set_column 0x05
+#define DW_LNS_negate_stmt 0x06
+#define DW_LNS_set_basic_block 0x07
+#define DW_LNS_const_add_pc 0x08
+#define DW_LNS_fixed_advance_pc 0x09
+#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
+#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
+#define DW_LNS_set_isa 0x0c /* DWARF3 */
+
+/* Line number extended opcode name. */
+#define DW_LNE_end_sequence 0x01
+#define DW_LNE_set_address 0x02
+#define DW_LNE_define_file 0x03
+#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
+
+/* HP extensions. */
+#define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */
+#define DW_LNE_HP_push_context 0x12 /* 18 HP */
+#define DW_LNE_HP_pop_context 0x13 /* 19 HP */
+#define DW_LNE_HP_set_file_line_column 0x14 /* 20 HP */
+#define DW_LNE_HP_set_routine_name 0x15 /* 21 HP */
+#define DW_LNE_HP_set_sequence 0x16 /* 22 HP */
+#define DW_LNE_HP_negate_post_semantics 0x17 /* 23 HP */
+#define DW_LNE_HP_negate_function_exit 0x18 /* 24 HP */
+#define DW_LNE_HP_negate_front_end_logical 0x19 /* 25 HP */
+#define DW_LNE_HP_define_proc 0x20 /* 32 HP */
+
+#define DW_LNE_lo_user 0x80 /* DWARF3 */
+#define DW_LNE_hi_user 0xff /* DWARF3 */
+
+/* These are known values for DW_LNS_set_isa. */
+#define DW_ISA_UNKNOWN 0
+/* The following two are ARM specific. */
+#define DW_ISA_ARM_thumb 1 /* ARM ISA */
+#define DW_ISA_ARM_arm 2 /* ARM ISA */
+
+/* Macro information. */
+#define DW_MACINFO_define 0x01
+#define DW_MACINFO_undef 0x02
+#define DW_MACINFO_start_file 0x03
+#define DW_MACINFO_end_file 0x04
+#define DW_MACINFO_vendor_ext 0xff
+
+/* CFA operator compaction (a space saving measure, see
+ the DWARF standard) means DW_CFA_extended and DW_CFA_nop
+ have the same value here. */
+#define DW_CFA_advance_loc 0x40
+#define DW_CFA_offset 0x80
+#define DW_CFA_restore 0xc0
+#define DW_CFA_extended 0
+
+#define DW_CFA_nop 0x00
+#define DW_CFA_set_loc 0x01
+#define DW_CFA_advance_loc1 0x02
+#define DW_CFA_advance_loc2 0x03
+#define DW_CFA_advance_loc4 0x04
+#define DW_CFA_offset_extended 0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined 0x07
+#define DW_CFA_same_value 0x08
+#define DW_CFA_register 0x09
+#define DW_CFA_remember_state 0x0a
+#define DW_CFA_restore_state 0x0b
+#define DW_CFA_def_cfa 0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset 0x0e
+#define DW_CFA_def_cfa_expression 0x0f /* DWARF3 */
+#define DW_CFA_expression 0x10 /* DWARF3 */
+#define DW_CFA_offset_extended_sf 0x11 /* DWARF3 */
+#define DW_CFA_def_cfa_sf 0x12 /* DWARF3 */
+#define DW_CFA_def_cfa_offset_sf 0x13 /* DWARF3 */
+#define DW_CFA_val_offset 0x14 /* DWARF3f */
+#define DW_CFA_val_offset_sf 0x15 /* DWARF3f */
+#define DW_CFA_val_expression 0x16 /* DWARF3f */
+
+#define DW_CFA_lo_user 0x1c
+#define DW_CFA_low_user 0x1c /* Incorrect spelling, do not use. */
+
+/* SGI/MIPS extension. */
+#define DW_CFA_MIPS_advance_loc8 0x1d /* MIPS */
+
+/* GNU extensions. */
+#define DW_CFA_GNU_window_save 0x2d /* GNU */
+#define DW_CFA_GNU_args_size 0x2e /* GNU */
+#define DW_CFA_GNU_negative_offset_extended 0x2f /* GNU */
+
+#define DW_CFA_high_user 0x3f
+
+/* GNU exception header encoding. See the Generic
+ Elf Specification of the Linux Standard Base (LSB).
+ http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
+ The upper 4 bits indicate how the value is to be applied.
+ The lower 4 bits indicate the format of the data.
+*/
+#define DW_EH_PE_absptr 0x00 /* GNU */
+#define DW_EH_PE_uleb128 0x01 /* GNU */
+#define DW_EH_PE_udata2 0x02 /* GNU */
+#define DW_EH_PE_udata4 0x03 /* GNU */
+#define DW_EH_PE_udata8 0x04 /* GNU */
+#define DW_EH_PE_sleb128 0x09 /* GNU */
+#define DW_EH_PE_sdata2 0x0A /* GNU */
+#define DW_EH_PE_sdata4 0x0B /* GNU */
+#define DW_EH_PE_sdata8 0x0C /* GNU */
+
+#define DW_EH_PE_pcrel 0x10 /* GNU */
+#define DW_EH_PE_textrel 0x20 /* GNU */
+#define DW_EH_PE_datarel 0x30 /* GNU */
+#define DW_EH_PE_funcrel 0x40 /* GNU */
+#define DW_EH_PE_aligned 0x50 /* GNU */
+
+#define DW_EH_PE_omit 0xff /* GNU. Means no value present. */
+
+
+/* Mapping from machine registers and pseudo-regs into the .debug_frame table.
+ DW_FRAME entries are machine specific. These describe
+ MIPS/SGI R3000, R4K, R4400 and all later MIPS/SGI IRIX machines.
+ They describe a mapping from hardware register number to
+ the number used in the table to identify that register.
+
+ The CFA (Canonical Frame Address) described in DWARF is called
+ the Virtual Frame Pointer on MIPS/SGI machines.
+
+ The DW_FRAME* names here are MIPS/SGI specfic.
+ Libdwarf interfaces defined in 2008 make the
+ frame definitions
+ here (and the fixed table sizes they imply) obsolete.
+ They are left here for compatibility.
+*/
+/* Default column used for CFA in the libdwarf reader client.
+ Assumes reg 0 never appears as
+ a register in DWARF information. Usable for MIPS,
+ but never a good idea, really. */
+#define DW_FRAME_CFA_COL 0
+
+#define DW_FRAME_REG1 1 /* integer reg 1 */
+#define DW_FRAME_REG2 2 /* integer reg 2 */
+#define DW_FRAME_REG3 3 /* integer reg 3 */
+#define DW_FRAME_REG4 4 /* integer reg 4 */
+#define DW_FRAME_REG5 5 /* integer reg 5 */
+#define DW_FRAME_REG6 6 /* integer reg 6 */
+#define DW_FRAME_REG7 7 /* integer reg 7 */
+#define DW_FRAME_REG8 8 /* integer reg 8 */
+#define DW_FRAME_REG9 9 /* integer reg 9 */
+#define DW_FRAME_REG10 10 /* integer reg 10 */
+#define DW_FRAME_REG11 11 /* integer reg 11 */
+#define DW_FRAME_REG12 12 /* integer reg 12 */
+#define DW_FRAME_REG13 13 /* integer reg 13 */
+#define DW_FRAME_REG14 14 /* integer reg 14 */
+#define DW_FRAME_REG15 15 /* integer reg 15 */
+#define DW_FRAME_REG16 16 /* integer reg 16 */
+#define DW_FRAME_REG17 17 /* integer reg 17 */
+#define DW_FRAME_REG18 18 /* integer reg 18 */
+#define DW_FRAME_REG19 19 /* integer reg 19 */
+#define DW_FRAME_REG20 20 /* integer reg 20 */
+#define DW_FRAME_REG21 21 /* integer reg 21 */
+#define DW_FRAME_REG22 22 /* integer reg 22 */
+#define DW_FRAME_REG23 23 /* integer reg 23 */
+#define DW_FRAME_REG24 24 /* integer reg 24 */
+#define DW_FRAME_REG25 25 /* integer reg 25 */
+#define DW_FRAME_REG26 26 /* integer reg 26 */
+#define DW_FRAME_REG27 27 /* integer reg 27 */
+#define DW_FRAME_REG28 28 /* integer reg 28 */
+#define DW_FRAME_REG29 29 /* integer reg 29 */
+#define DW_FRAME_REG30 30 /* integer reg 30 */
+#define DW_FRAME_REG31 31 /* integer reg 31, aka ra */
+
+ /* MIPS1, 2 have only some of these 64-bit registers.
+ ** MIPS1 save/restore takes 2 instructions per 64-bit reg, and
+ ** in that case, the register is considered stored after the second
+ ** swc1.
+ */
+#define DW_FRAME_FREG0 32 /* 64-bit floating point reg 0 */
+#define DW_FRAME_FREG1 33 /* 64-bit floating point reg 1 */
+#define DW_FRAME_FREG2 34 /* 64-bit floating point reg 2 */
+#define DW_FRAME_FREG3 35 /* 64-bit floating point reg 3 */
+#define DW_FRAME_FREG4 36 /* 64-bit floating point reg 4 */
+#define DW_FRAME_FREG5 37 /* 64-bit floating point reg 5 */
+#define DW_FRAME_FREG6 38 /* 64-bit floating point reg 6 */
+#define DW_FRAME_FREG7 39 /* 64-bit floating point reg 7 */
+#define DW_FRAME_FREG8 40 /* 64-bit floating point reg 8 */
+#define DW_FRAME_FREG9 41 /* 64-bit floating point reg 9 */
+#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */
+#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */
+#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */
+#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */
+#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */
+#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */
+#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */
+#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */
+#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */
+#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */
+#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */
+#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */
+#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */
+#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */
+#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */
+#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */
+#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */
+#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */
+#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */
+#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */
+#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */
+#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */
+
+/* ***IMPORTANT NOTE, TARGET DEPENDENCY ****
+ The following 4 #defines are dependent on
+ the target cpu(s) that you apply libdwarf to.
+ Ensure that DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL
+ do not conflict with the range [0-DW_FRAME_STATIC_LINK].
+ The value 63 works for MIPS cpus at least up to the R16000.
+
+ For a cpu with more than 63 real registers
+ DW_FRAME_HIGHEST_NORMAL_REGISTER
+ must be increased for things to work properly!
+ Also ensure that DW_FRAME_UNDEFINED_VAL DW_FRAME_SAME_VAL
+ are not in the range [0-DW_FRAME_STATIC_LINK]
+
+ Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than
+ is strictly needed is safe.
+
+*/
+
+#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER
+#define DW_FRAME_HIGHEST_NORMAL_REGISTER 63
+#endif
+/* This is the number of columns in the Frame Table.
+ This constant should
+ be kept in sync with DW_REG_TABLE_SIZE defined in libdwarf.h
+ It must also be large enough to be beyond the highest
+ compiler-defined-register (meaning DW_FRAME_RA_COL DW_FRAME_STATIC_LINK
+ in the MIPS/IRIX case */
+#ifndef DW_FRAME_LAST_REG_NUM
+#define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3)
+#endif
+
+
+/* Column recording ra (return address from a function call).
+ This is common to many architectures, but as a 'simple register'
+ is not necessarily adequate for all architectures.
+ For MIPS/IRIX this register number is actually recorded on disk
+ in the .debug_frame section.
+ */
+#define DW_FRAME_RA_COL (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1)
+
+/* Column recording static link applicable to up-level
+ addressing, as in IRIX mp code, pascal, etc.
+ This is common to many architectures but
+ is not necessarily adequate for all architectures.
+ For MIPS/IRIX this register number is actually recorded on disk
+ in the .debug_frame section.
+*/
+#define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2)
+
+
+
+/*
+ DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL are
+ never on disk, just generated by libdwarf. See libdwarf.h
+ for their values.
+*/
+
+
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DWARF_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_abbrev.c b/usr/src/lib/libdwarf/common/dwarf_abbrev.c
new file mode 100644
index 0000000000..c2ae361f33
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_abbrev.c
@@ -0,0 +1,259 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the above address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_abbrev.h"
+
+int
+dwarf_get_abbrev(Dwarf_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Abbrev * returned_abbrev,
+ Dwarf_Unsigned * length,
+ Dwarf_Unsigned * abbr_count, Dwarf_Error * error)
+{
+ Dwarf_Small *abbrev_ptr = 0;
+ Dwarf_Small *abbrev_section_end = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Abbrev ret_abbrev = 0;
+ Dwarf_Unsigned labbr_count = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (dbg->de_debug_abbrev.dss_data == 0) {
+ /* Loads abbrev section (and .debug_info as we do those
+ together). */
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ if (offset >= dbg->de_debug_abbrev.dss_size) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+
+ ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, DW_DLA_ABBREV, 1);
+ if (ret_abbrev == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ ret_abbrev->ab_dbg = dbg;
+ if (returned_abbrev == 0 || abbr_count == 0) {
+ dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
+ _dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ *abbr_count = 0;
+ if (length != NULL)
+ *length = 1;
+
+ abbrev_ptr = dbg->de_debug_abbrev.dss_data + offset;
+ abbrev_section_end =
+ dbg->de_debug_abbrev.dss_data + dbg->de_debug_abbrev.dss_size;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp);
+ ret_abbrev->ab_code = (Dwarf_Word) utmp;
+ if (ret_abbrev->ab_code == 0) {
+ *returned_abbrev = ret_abbrev;
+ *abbr_count = 0;
+ if (length) {
+ *length = 1;
+ }
+ return (DW_DLV_OK);
+ }
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp);
+ ret_abbrev->ab_tag = utmp;
+ ret_abbrev->ab_has_child = *(abbrev_ptr++);
+ ret_abbrev->ab_abbrev_ptr = abbrev_ptr;
+
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+
+ if (attr != 0)
+ (labbr_count)++;
+
+ } while (abbrev_ptr < abbrev_section_end &&
+ (attr != 0 || attr_form != 0));
+
+ if (abbrev_ptr > abbrev_section_end) {
+ dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
+ _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ if (length != NULL)
+ *length = abbrev_ptr - dbg->de_debug_abbrev.dss_data - offset;
+
+ *returned_abbrev = ret_abbrev;
+ *abbr_count = labbr_count;
+ return (DW_DLV_OK);
+}
+
+int
+dwarf_get_abbrev_code(Dwarf_Abbrev abbrev,
+ Dwarf_Unsigned * returned_code,
+ Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_code = abbrev->ab_code;
+ return (DW_DLV_OK);
+}
+
+/* DWARF defines DW_TAG_hi_user as 0xffff so no tag should be
+ over 16 bits. */
+int
+dwarf_get_abbrev_tag(Dwarf_Abbrev abbrev,
+ Dwarf_Half * returned_tag, Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_tag = abbrev->ab_tag;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_get_abbrev_children_flag(Dwarf_Abbrev abbrev,
+ Dwarf_Signed * returned_flag,
+ Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_flag = abbrev->ab_has_child;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_get_abbrev_entry(Dwarf_Abbrev abbrev,
+ Dwarf_Signed index,
+ Dwarf_Half * returned_attr_num,
+ Dwarf_Signed * form,
+ Dwarf_Off * offset, Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Byte_Ptr abbrev_end = 0;
+ Dwarf_Byte_Ptr mark_abbrev_ptr = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+
+ if (index < 0)
+ return (DW_DLV_NO_ENTRY);
+
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (abbrev->ab_code == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if (abbrev->ab_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ abbrev_ptr = abbrev->ab_abbrev_ptr;
+ abbrev_end =
+ abbrev->ab_dbg->de_debug_abbrev.dss_data +
+ abbrev->ab_dbg->de_debug_abbrev.dss_size;
+
+ for (attr = 1, attr_form = 1;
+ index >= 0 && abbrev_ptr < abbrev_end && (attr != 0 ||
+ attr_form != 0);
+ index--) {
+ Dwarf_Unsigned utmp4;
+
+ mark_abbrev_ptr = abbrev_ptr;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp4);
+ attr = (Dwarf_Half) utmp4;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp4);
+ attr_form = (Dwarf_Half) utmp4;
+ }
+
+ if (abbrev_ptr >= abbrev_end) {
+ _dwarf_error(abbrev->ab_dbg, error, DW_DLE_ABBREV_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ if (index >= 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if (form != NULL)
+ *form = attr_form;
+ if (offset != NULL)
+ *offset = mark_abbrev_ptr - abbrev->ab_dbg->de_debug_abbrev.dss_data;
+
+ *returned_attr_num = (attr);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_abbrev.h b/usr/src/lib/libdwarf/common/dwarf_abbrev.h
new file mode 100644
index 0000000000..b525924c83
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_abbrev.h
@@ -0,0 +1,55 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+/* In a given CU, one of these is (eventually) set up
+ for every abbreviation we need to find (and for all.
+ those ealier in the abbreviations for that CU).
+ So we don't want elements needlessly big.
+*/
+struct Dwarf_Abbrev_s {
+ /* No TAG should exceed DW_TAG_hi_user, 0xffff, but
+ we do allow a larger value here. */
+ Dwarf_Word ab_tag;
+ /* Abbreviations are numbered (normally sequentially from
+ 1 and so 16 bits is not enough! */
+ Dwarf_Word ab_code;
+ Dwarf_Small ab_has_child;
+ Dwarf_Byte_Ptr ab_abbrev_ptr;
+ Dwarf_Debug ab_dbg;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_addr_finder.c b/usr/src/lib/libdwarf/common/dwarf_addr_finder.c
new file mode 100644
index 0000000000..2fadefc1ea
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_addr_finder.c
@@ -0,0 +1,685 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* This code used by SGI-IRIX rqs processing, not needed by
+ any other system or application.
+*/
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include <dwarf.h>
+#include <libdwarf.h>
+#include "dwarf_base_types.h"
+#include "dwarf_alloc.h"
+#include "dwarf_opaque.h"
+#include "dwarf_arange.h"
+#include "dwarf_line.h"
+#include "dwarf_frame.h"
+#include <cmplrs/dwarf_addr_finder.h>
+#include "dwarf_error.h"
+
+typedef unsigned long long ull;
+
+static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die,
+ int *errval);
+static int
+ handle_debug_info(Dwarf_Debug dbg, int *errval);
+static int
+ handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+ handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+ handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+ handle_debug_loc(void);
+
+
+static Dwarf_addr_callback_func send_addr_note;
+
+int
+_dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,
+ Dwarf_addr_callback_func cb_func, int *dwerr)
+{
+
+ Dwarf_Error err = 0;
+ Dwarf_Debug dbg = 0;
+ int res = 0;
+ int errval = 0;
+ int sections_found = 0;
+
+ res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0,
+ /* errarg */ 0, &dbg, &err);
+ if (res == DW_DLV_ERROR) {
+ int errv = (int) dwarf_errno(err);
+
+ return errv;
+ }
+ if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+
+ send_addr_note = cb_func;
+
+ res = handle_debug_info(dbg, &errval);
+ switch (res) {
+ case DW_DLV_OK:
+ ++sections_found;
+ break;
+ case DW_DLV_NO_ENTRY:
+
+ break;
+ default:
+ case DW_DLV_ERROR:
+ dwarf_finish(dbg, &err);
+ *dwerr = errval;
+ return res;
+ }
+
+ res = handle_debug_aranges(dbg, cb_func, &errval);
+ switch (res) {
+ case DW_DLV_OK:
+ ++sections_found;
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ dwarf_finish(dbg, &err);
+ *dwerr = errval;
+ return res;
+ }
+ res = handle_debug_frame(dbg, cb_func, &errval);
+ switch (res) {
+ case DW_DLV_OK:
+ ++sections_found;
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ dwarf_finish(dbg, &err);
+ *dwerr = errval;
+ return res;
+ }
+
+ res = handle_debug_loc(); /* does nothing */
+ switch (res) {
+ case DW_DLV_OK:
+ ++sections_found;
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ /* IMPOSSIBLE : handle_debug_loc cannot return this */
+ dwarf_finish(dbg, &err);
+ *dwerr = errval;
+ return res;
+ }
+
+
+
+ *dwerr = 0;
+ res = dwarf_finish(dbg, &err);
+ if (res == DW_DLV_ERROR) {
+ *dwerr = (int) dwarf_errno(err);
+ return DW_DLV_ERROR;
+ }
+ if (sections_found == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ return DW_DLV_OK;
+
+}
+
+/*
+ Return DW_DLV_OK, ERROR, or NO_ENTRY.
+*/
+static int
+handle_debug_info(Dwarf_Debug dbg, int *errval)
+{
+ Dwarf_Unsigned nxtoff = 1;
+ Dwarf_Unsigned hdr_length;
+ Dwarf_Half version_stamp;
+ Dwarf_Unsigned abbrev_offset;
+ Dwarf_Half addr_size;
+ Dwarf_Error err;
+ int terminate_now = 0;
+ int res = 0;
+ Dwarf_Die sibdie;
+ int sibres;
+ int nres = DW_DLV_OK;
+
+
+ for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
+ &abbrev_offset,
+ &addr_size, &nxtoff, &err);
+ terminate_now == 0 && nres == DW_DLV_OK;
+ nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
+ &abbrev_offset,
+ &addr_size, &nxtoff, &err)
+ ) {
+
+ Dwarf_Die curdie = 0;
+
+ /* try to get the compilation unit die */
+ sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err);
+ if (sibres == DW_DLV_OK) {
+ res = do_this_die_and_dealloc(dbg, sibdie, errval);
+ switch (res) {
+ case DW_DLV_OK:
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ return DW_DLV_ERROR;
+ }
+ } else if (sibres == DW_DLV_ERROR) {
+ *errval = (int) dwarf_errno(err);
+ return DW_DLV_ERROR;
+ } else {
+ /* NO ENTRY! */
+ /* impossible? */
+ }
+
+ }
+ if (nres == DW_DLV_ERROR) {
+ int localerr = (int) dwarf_errno(err);
+
+ *errval = localerr;
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_OK;
+}
+
+static int
+ might_have_addr[] = {
+ DW_AT_high_pc,
+ DW_AT_low_pc,
+};
+static int
+ might_have_locdesc[] = {
+ DW_AT_segment,
+ DW_AT_return_addr,
+ DW_AT_frame_base,
+ DW_AT_static_link,
+ DW_AT_data_member_location,
+ DW_AT_string_length,
+ DW_AT_location,
+ DW_AT_use_location,
+ DW_AT_vtable_elem_location,
+};
+
+/*
+ Return DW_DLV_OK if handling this went ok.
+*/
+static int
+handle_attr_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
+ Dwarf_Error * perr)
+{
+ int res = DW_DLV_OK;
+ Dwarf_Off offset;
+ Dwarf_Addr addr;
+ Dwarf_Half form;
+ int ares;
+
+ Dwarf_Attribute attr;
+
+ ares = dwarf_attr(die, attrnum, &attr, perr);
+ if (ares == DW_DLV_OK) {
+ int formres = dwarf_whatform(attr, &form, perr);
+
+ switch (formres) {
+ case DW_DLV_OK:
+ break;
+ case DW_DLV_ERROR:
+ case DW_DLV_NO_ENTRY: /* impossible. */
+ return formres;
+
+ }
+
+ switch (form) {
+ case DW_FORM_ref_addr:
+ case DW_FORM_addr:
+ res = dwarf_attr_offset(die, attr, &offset, perr);
+ if (res == DW_DLV_OK) {
+ ares = dwarf_formaddr(attr, &addr, perr);
+ if (ares == DW_DLV_OK) {
+ send_addr_note(DW_SECTION_INFO, offset, addr);
+ } else if (ares == DW_DLV_ERROR) {
+ return ares;
+ } /* no entry: ok. */
+ } else {
+ res = DW_DLV_ERROR; /* NO_ENTRY is impossible. */
+ }
+ break;
+
+ default:
+ /* surprising! An error? */
+
+ ; /* do nothing */
+ }
+ dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+
+ } else {
+ res = ares;
+ }
+ return res;
+}
+
+/*
+ Return DW_DLV_OK if handling this went ok.
+*/
+static int
+handle_attr_locdesc(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
+ Dwarf_Error * perr)
+{
+ int retval = DW_DLV_OK;
+ Dwarf_Attribute attr;
+ Dwarf_Locdesc *llbuf;
+ Dwarf_Signed i;
+ Dwarf_Off offset;
+ Dwarf_Loc *locp;
+ unsigned int entindx;
+ int res;
+ int ares;
+
+
+ ares = dwarf_attr(die, attrnum, &attr, perr);
+ if (ares == DW_DLV_OK) {
+ Dwarf_Half form;
+ int fres = dwarf_whatform(attr, &form, perr);
+
+ if (fres == DW_DLV_OK) {
+ switch (form) {
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /* must be location description */
+ res = dwarf_attr_offset(die, attr, &offset, perr);
+ llbuf = 0;
+ if (res == DW_DLV_OK) {
+ Dwarf_Signed count;
+ int lres = dwarf_loclist(attr, &llbuf, &count, perr);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (count != 1) {
+ /* this cannot happen! */
+ /* perr? */
+ _dwarf_error(dbg, perr,
+ DW_DLE_LOCDESC_COUNT_WRONG);
+ retval = DW_DLV_ERROR;
+ return retval;
+ }
+ for (i = 0; i < count; ++i) {
+ unsigned int ents = llbuf[i].ld_cents;
+
+ locp = llbuf[i].ld_s;
+ for (entindx = 0; entindx < ents; entindx++) {
+ Dwarf_Loc *llocp;
+
+ llocp = locp + entindx;
+ if (llocp->lr_atom == DW_OP_addr) {
+ send_addr_note(DW_SECTION_INFO, offset +
+ llocp->lr_offset + 1
+ /* The offset is the
+ offset of the atom,
+ ** and we know the
+ addr is 1 past it. */
+ , llocp->lr_number);
+ }
+ }
+ }
+
+
+ if (count > 0) {
+ for (i = 0; i < count; ++i) {
+ dwarf_dealloc(dbg, llbuf[i].ld_s,
+ DW_DLA_LOC_BLOCK);
+ }
+ dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
+ }
+ } else {
+ retval = res;
+ }
+ break;
+
+ default:
+ /* must be a const offset in debug_loc */
+ ; /* do nothing */
+ }
+ dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+ } /* else error or no entry */
+ retval = fres;
+ } else {
+ retval = ares;
+ }
+ return retval;
+}
+
+/*
+ Return DW_DLV_OK, or DW_DLV_ERROR
+
+ Handle the addrs in a single die.
+*/
+static int
+process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval)
+{
+ Dwarf_Error err;
+ Dwarf_Half i;
+ Dwarf_Half newattrnum;
+ int res;
+ int tres;
+ Dwarf_Half ltag;
+
+ Dwarf_Off doff;
+ int doffres = dwarf_dieoffset(newdie, &doff, &err);
+
+ if (doffres != DW_DLV_OK) {
+ if (doffres == DW_DLV_ERROR) {
+ *errval = (int) dwarf_errno(err);
+ }
+ return doffres;
+ }
+ tres = dwarf_tag(newdie, &ltag, &err);
+ if (tres != DW_DLV_OK) {
+ return tres;
+ }
+ if (DW_TAG_compile_unit == ltag) {
+ /* because of the way the dwarf_line code works, we do lines
+ only per compile unit. This may turn out to be wrong if
+ we have lines left unconnected to a CU. of course such
+ lines will not, at present, be used by gnome. This is
+ not ideal as coded due to the dwarf_line.c issue. */
+ int lres = handle_debug_line(dbg, newdie, send_addr_note, errval);
+ if (lres == DW_DLV_ERROR) {
+ return lres;
+ }
+ }
+
+ for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) {
+ int resattr;
+ Dwarf_Bool hasattr;
+
+ newattrnum = might_have_addr[i];
+ err = 0;
+ resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
+ if (DW_DLV_OK == resattr) {
+ if (hasattr) {
+ res = handle_attr_addr(dbg, newdie, newattrnum, &err);
+ if (res != DW_DLV_OK) {
+ *errval = (int) dwarf_errno(err);
+ return DW_DLV_ERROR;
+ }
+ }
+ } else {
+ if (resattr == DW_DLV_ERROR) {
+ *errval = (int) dwarf_errno(err);
+ return resattr;
+ }
+ }
+ }
+ for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) {
+ int resattr;
+ Dwarf_Bool hasattr;
+
+ newattrnum = might_have_locdesc[i];
+ err = 0;
+ resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
+ if (DW_DLV_OK == resattr) {
+ if (hasattr) {
+ res =
+ handle_attr_locdesc(dbg, newdie, newattrnum, &err);
+ if (res != DW_DLV_OK) {
+ *errval = (int) dwarf_errno(err);
+ return DW_DLV_ERROR;
+ }
+ }
+ } else {
+ if (resattr == DW_DLV_ERROR) {
+ *errval = (int) dwarf_errno(err);
+ return resattr;
+ }
+ }
+ }
+
+ return DW_DLV_OK;
+}
+
+/*
+ Handle siblings as a list,
+ Do children by recursing.
+ Effectively this is walking the tree preorder.
+
+ This dealloc's any die passed to it, so the
+ caller should not do that dealloc.
+ It seems more logical to have the one causing
+ the alloc to do the dealloc, but that way this
+ routine became a mess.
+
+*/
+static int
+do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval)
+{
+
+ Dwarf_Die prevdie = 0;
+ Dwarf_Die newdie = die;
+ Dwarf_Error err = 0;
+ int res = 0;
+ int sibres = DW_DLV_OK;
+ int tres = DW_DLV_OK;
+ Dwarf_Die sibdie;
+
+ while (sibres == DW_DLV_OK) {
+ Dwarf_Die ch_die;
+
+
+ res = process_this_die_attrs(dbg, newdie, errval);
+ switch (res) {
+ case DW_DLV_OK:
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ if (prevdie) {
+ dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+ prevdie = 0;
+ }
+ return DW_DLV_ERROR;
+ }
+
+ tres = dwarf_child(newdie, &ch_die, &err);
+
+ if (tres == DW_DLV_OK) {
+ res = do_this_die_and_dealloc(dbg, ch_die, errval);
+ switch (res) {
+ case DW_DLV_OK:
+ break;
+ case DW_DLV_NO_ENTRY:
+ break;
+ default:
+ case DW_DLV_ERROR:
+ if (prevdie) {
+ dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+ prevdie = 0;
+ }
+ return DW_DLV_ERROR;
+ }
+ } else if (tres == DW_DLV_ERROR) {
+ /* An error! */
+ *errval = (int) dwarf_errno(err);
+ if (prevdie) {
+ dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+ prevdie = 0;
+ }
+ dwarf_dealloc(dbg, err, DW_DLA_ERROR);
+ return DW_DLV_ERROR;
+ } /* else was NO ENTRY */
+ prevdie = newdie;
+ sibdie = 0;
+ sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err);
+ if (prevdie) {
+ dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+ prevdie = 0;
+ }
+ newdie = sibdie;
+
+ }
+ if (sibres == DW_DLV_NO_ENTRY) {
+ return DW_DLV_OK;
+ }
+ /* error. */
+ *errval = (int) dwarf_errno(err);
+ if (prevdie) {
+ dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+ prevdie = 0;
+ }
+ dwarf_dealloc(dbg, err, DW_DLA_ERROR);
+ return DW_DLV_ERROR;
+
+}
+
+
+static int
+handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
+ int *errval)
+{
+ int retval = DW_DLV_OK;
+ int res;
+ Dwarf_Error err;
+ Dwarf_Addr *addrlist;
+ Dwarf_Off *offsetlist;
+ Dwarf_Signed count;
+ int i;
+
+ res =
+ _dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist,
+ &count, &err);
+ if (res == DW_DLV_OK) {
+ for (i = 0; i < count; i++) {
+ cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]);
+ }
+ dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
+ dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ retval = res;
+ } else {
+ *errval = (int) dwarf_errno(err);
+ retval = DW_DLV_ERROR;
+ }
+ return retval;
+
+}
+static int
+handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
+ int *errval)
+{
+ int retval = DW_DLV_OK;
+ Dwarf_Error err;
+ Dwarf_Addr *aranges;
+ Dwarf_Signed count;
+ int indx;
+ Dwarf_Off *offsets;
+
+ retval =
+ _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count,
+ &err);
+ if (retval == DW_DLV_OK) {
+ if (count == 0) {
+ retval = DW_DLV_NO_ENTRY;
+ } else {
+ for (indx = 0; indx < count; indx++) {
+ cb_func(DW_SECTION_ARANGES, offsets[indx],
+ aranges[indx]);
+ }
+ }
+ dwarf_dealloc(dbg, aranges, DW_DLA_ADDR);
+ dwarf_dealloc(dbg, offsets, DW_DLA_ADDR);
+ } else if (retval == DW_DLV_NO_ENTRY) {
+ ; /* do nothing */
+ } else {
+ *errval = (int) dwarf_errno(err);
+ retval = DW_DLV_ERROR;
+ }
+ return retval;
+}
+static int
+handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die,
+ Dwarf_addr_callback_func cb_func, int *errval)
+{
+ int retval = DW_DLV_OK;
+ int res;
+ Dwarf_Error err;
+ Dwarf_Addr *addrlist;
+ Dwarf_Off *offsetlist;
+ Dwarf_Unsigned count;
+ Dwarf_Unsigned i;
+
+ res =
+ _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist,
+ &count, &err);
+ if (res == DW_DLV_OK) {
+ for (i = 0; i < count; i++) {
+ cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]);
+
+ }
+ dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
+ dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ retval = res;
+ } else {
+ *errval = (int) dwarf_errno(err);
+ retval = DW_DLV_ERROR;
+ }
+ return retval;
+}
+
+/*
+ We need to add support for this. Currently we do not
+ generate this section.
+ FIX!
+*/
+static int
+handle_debug_loc(void)
+{
+ int retval = DW_DLV_NO_ENTRY;
+
+ return retval;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_alloc.c b/usr/src/lib/libdwarf/common/dwarf_alloc.c
new file mode 100644
index 0000000000..ddb423e841
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_alloc.c
@@ -0,0 +1,1258 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+#undef DEBUG
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "malloc_check.h"
+
+/*
+ These files are included to get the sizes
+ of structs to set the ah_bytes_one_struct field
+ of the Dwarf_Alloc_Hdr_s structs for each
+ allocation type.
+*/
+#include "dwarf_line.h"
+#include "dwarf_global.h"
+#include "dwarf_arange.h"
+#include "dwarf_abbrev.h"
+#include "dwarf_die_deliv.h"
+#include "dwarf_frame.h"
+#include "dwarf_loc.h"
+#include "dwarf_funcs.h"
+#include "dwarf_types.h"
+#include "dwarf_vars.h"
+#include "dwarf_weaks.h"
+
+
+static void _dwarf_free_special_error(Dwarf_Ptr space);
+
+#ifdef DWARF_SIMPLE_MALLOC
+static void _dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg,
+ Dwarf_Ptr addr,
+ unsigned long size,
+ short alloc_type);
+static void _dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg,
+ Dwarf_Ptr space,
+ short alloc_type);
+void _dwarf_simple_malloc_botch(int err);
+
+#endif /* DWARF_SIMPLE_MALLOC */
+
+
+
+
+/*
+ This macro adds the size of a pointer to the size of a
+ struct that is given to it. It rounds up the size to
+ be a multiple of the size of a pointer. This is done
+ so that every struct returned by _dwarf_get_alloc()
+ can be preceded by a pointer to the chunk it came from.
+ Before allocating, it checks if the size of struct is less than
+ the size of a pointer. If yes, it returns the size
+ of 2 pointers. The returned size should be at least
+ the size of 2 pointers, since the first points to the
+ chunk the struct was allocated from, and the second
+ is used to link the free list.
+
+ We want DW_RESERVE to be at least the size of
+ a long long and at least the size of a pointer because
+ our struct has a long long and we want that aligned right.
+ Now Standard C defines long long as 8 bytes, so lets
+ make that standard. It will become unworkable when
+ long long or pointer grows beyound 8 bytes.
+ Unclear what to do with wierd requirements, like
+ 36 bit pointers.
+
+
+*/
+#define DW_RESERVE 8
+
+/* Round size up to the next multiple of DW_RESERVE bytes
+*/
+#define ROUND_SIZE(inputsize) \
+ (((inputsize) % (DW_RESERVE)) == 0 ? \
+ (inputsize): \
+ ((inputsize) + \
+ (DW_RESERVE) - ((inputsize) % (DW_RESERVE)) ))
+
+#define ROUND_SIZE_WITH_POINTER(i_size) (ROUND_SIZE(i_size) + DW_RESERVE)
+
+/* SMALL_ALLOC is for trivia where allocation is a waste.
+ Things that should be removed, really. */
+#define SMALL_ALLOC 2
+
+/* BASE_ALLOC is where a basic allocation makes sense, but 'not too large'.
+ No thorough evaluation of this value has been done, though
+ it was found wasteful of memory to have BASE_ALLOC be as large as
+ BIG_ALLOC. */
+#define BASE_ALLOC 64
+
+/* BIG_ALLOC is where a larger-than-BASE_ALLOC
+ allocation makes sense, but still 'not too large'.
+ No thorough evaluation of this value has been done. */
+#define BIG_ALLOC 128
+
+/* This translates into de_alloc_hdr index
+** the 0,1,1 entries are special: they don't use the
+** table values at all.
+** Rearranging the DW_DLA values would break binary compatibility
+** so that is not an option.
+*/
+struct ial_s {
+ int ia_al_num; /* Index into de_alloc_hdr table. */
+
+ /* In bytes, one struct instance. This does not account for extra
+ space needed per block, but that (DW_RESERVE) will be added in
+ later where it is needed (DW_RESERVE space never added in here).
+ */
+ int ia_struct_size;
+
+
+ /* Number of instances per alloc block. MUST be > 0. */
+ int ia_base_count;
+
+ int (*specialconstructor) (Dwarf_Debug, void *);
+ void (*specialdestructor) (void *);
+};
+
+static const
+struct ial_s index_into_allocated[ALLOC_AREA_INDEX_TABLE_MAX] = {
+ {0, 1, 1, 0, 0}, /* none */
+ {0, 1, 1, 0, 0}, /* 1 DW_DLA_STRING */
+ {1, sizeof(Dwarf_Loc), BASE_ALLOC, 0, 0}
+ , /* 2 DW_DLA_LOC */
+ {2, sizeof(Dwarf_Locdesc), BASE_ALLOC, 0, 0}
+ , /* 3 DW_DLA_LOCDESC */
+ {0, 1, 1, 0, 0}
+ , /* not used *//* 4 DW_DLA_ELLIST */
+ {0, 1, 1, 0, 0}
+ , /* not used *//* 5 DW_DLA_BOUNDS */
+ {3, sizeof(Dwarf_Block), BASE_ALLOC, 0, 0}
+ , /* 6 DW_DLA_BLOCK */
+ {0, 1, 1, 0, 0}
+ , /* the actual dwarf_debug structure *//* 7 DW_DLA_DEBUG */
+ {4, sizeof(struct Dwarf_Die_s), BIG_ALLOC, 0, 0}, /* 8 DW_DLA_DIE
+ */
+ {5, sizeof(struct Dwarf_Line_s), BIG_ALLOC, 0, 0}, /* 9
+ DW_DLA_LINE */
+ {6, sizeof(struct Dwarf_Attribute_s), BIG_ALLOC * 2, 0, 0},
+ /* 10 DW_DLA_ATTR */
+ {0, 1, 1, 0, 0}, /* not used *//* 11 DW_DLA_TYPE */
+ {0, 1, 1, 0, 0}, /* not used *//* 12 DW_DLA_SUBSCR */
+ {7, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 13
+ DW_DLA_GLOBAL
+ */
+ {8, sizeof(struct Dwarf_Error_s), BASE_ALLOC, 0, 0}, /* 14
+ DW_DLA_ERROR
+ */
+ {0, 1, 1, 0, 0}, /* 15 DW_DLA_LIST */
+ {0, 1, 1, 0, 0}, /* not used *//* 16 DW_DLA_LINEBUF */
+ {9, sizeof(struct Dwarf_Arange_s), BASE_ALLOC, 0, 0}, /* 17
+ DW_DLA_ARANGE
+ */
+ {10, sizeof(struct Dwarf_Abbrev_s), BIG_ALLOC, 0, 0}, /* 18
+ DW_DLA_ABBREV
+ */
+ {11, sizeof(Dwarf_Frame_Op), BIG_ALLOC, 0, 0}
+ , /* 19 DW_DLA_FRAME_OP */
+ {12, sizeof(struct Dwarf_Cie_s), BASE_ALLOC, 0, 0}, /* 20
+ DW_DLA_CIE */
+ {13, sizeof(struct Dwarf_Fde_s), BASE_ALLOC, 0, 0}, /* 21 DW_DLA_FDE */
+ {0, 1, 1, 0, 0}, /* 22 DW_DLA_LOC_BLOCK */
+ {0, 1, 1, 0, 0}, /* 23 DW_DLA_FRAME_BLOCK */
+ {14, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 24 DW_DLA_FUNC
+ UNUSED */
+ {15, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 25
+ DW_DLA_TYPENAME
+ UNUSED */
+ {16, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 26 DW_DLA_VAR
+ UNUSED */
+ {17, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 27 DW_DLA_WEAK
+ UNUSED */
+ {0, 1, 1, 0, 0}, /* 28 DW_DLA_ADDR */
+ {0, 1,1,0,0 }, /* 29 DW_DLA_RANGES */
+
+ /* The following DW_DLA data types
+ are known only inside libdwarf. */
+
+ {18, sizeof(struct Dwarf_Abbrev_List_s), BIG_ALLOC, 0, 0},
+ /* 30 DW_DLA_ABBREV_LIST */
+
+ {19, sizeof(struct Dwarf_Chain_s), BIG_ALLOC, 0, 0}, /* 31 DW_DLA_CHAIN */
+ {20, sizeof(struct Dwarf_CU_Context_s), BASE_ALLOC, 0, 0},
+ /* 32 DW_DLA_CU_CONTEXT */
+ {21, sizeof(struct Dwarf_Frame_s), BASE_ALLOC,
+ _dwarf_frame_constructor,
+ _dwarf_frame_destructor}, /* 33 DW_DLA_FRAME */
+ {22, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 34 DW_DLA_GLOBAL_CONTEXT */
+ {23, sizeof(struct Dwarf_File_Entry_s), BASE_ALLOC, 0, 0}, /* 34 */
+ /* 35 DW_DLA_FILE_ENTRY */
+ {24, sizeof(struct Dwarf_Line_Context_s), BASE_ALLOC, 0, 0},
+ /* 36 DW_DLA_LINE_CONTEXT */
+ {25, sizeof(struct Dwarf_Loc_Chain_s), BASE_ALLOC, 0, 0}, /* 36 */
+ /* 37 DW_DLA_LOC_CHAIN */
+
+ {26, sizeof(struct Dwarf_Hash_Table_s),BASE_ALLOC, 0, 0}, /* 37 */
+ /* 38 DW_DLA_HASH_TABLE */
+
+/* The following really use Global struct: used to be unique struct
+ per type, but now merged (11/99). The opaque types
+ are visible in the interface. The types for
+ DW_DLA_FUNC,
+ DW_DLA_TYPENAME, DW_DLA_VAR, DW_DLA_WEAK also use
+ the global types.
+
+*/
+ {27, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 39 DW_DLA_FUNC_CONTEXT */
+ {28, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 40 DW_DLA_TYPENAME_CONTEXT */
+ {29, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 41 DW_DLA_VAR_CONTEXT */
+ {30, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 42 DW_DLA_WEAK_CONTEXT */
+ {31, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 43 DW_DLA_PUBTYPES_CONTEXT DWARF3 */
+
+ {0,1,1,0,0 },
+ /* 44 DW_DLA_HASH_TABLE_ENTRY */
+
+
+};
+
+#ifndef DWARF_SIMPLE_MALLOC
+
+/*
+ This function is given a pointer to the header
+ structure that is used to allocate 1 struct of
+ the type given by alloc_type. It first checks
+ if a struct is available in its free list. If
+ not, it checks if 1 is available in its blob,
+ which is a chunk of memory that is reserved for
+ its use. If not, it malloc's a chunk. The
+ initial part of it is used to store the end
+ address of the chunk, and also to keep track
+ of the number of free structs in that chunk.
+ This information is used for freeing the chunk
+ when all the structs in it are free.
+
+ Assume all input arguments have been validated.
+
+ This function can be used only to allocate 1
+ struct of the given type.
+
+ It returns a pointer to the struct that the
+ user can use. It returns NULL only when it
+ is out of free structs, and cannot malloc
+ any more. The struct returned is zero-ed.
+
+ A pointer to the chunk that the struct belongs
+ to is stored in the bytes preceding the
+ returned address. Since this pointer it
+ never overwritten, when a struct is allocated
+ from the free_list this pointer does not
+ have to be written. In the 2 other cases,
+ where the struct is allocated from a new
+ chunk, or the blob, a pointer to the chunk
+ is written.
+*/
+static Dwarf_Ptr
+_dwarf_find_memory(Dwarf_Alloc_Hdr alloc_hdr)
+{
+ /* Pointer to the struct allocated. */
+ Dwarf_Small *ret_mem = 0;
+
+ /* Pointer to info about chunks allocated. */
+ Dwarf_Alloc_Area alloc_area;
+
+ /* Size of chunk malloc'ed when no free structs left. */
+ Dwarf_Signed mem_block_size;
+
+ /* Pointer to block malloc'ed. */
+ Dwarf_Small *mem_block;
+
+ /*
+ Check the alloc_area from which the last allocation was made
+ (most recent new block). If that is not successful, then search
+ the list of alloc_area's from alloc_header. */
+ alloc_area = alloc_hdr->ah_last_alloc_area;
+ if (alloc_area == NULL || alloc_area->aa_free_structs_in_chunk == 0)
+ for (alloc_area = alloc_hdr->ah_alloc_area_head;
+ alloc_area != NULL; alloc_area = alloc_area->aa_next) {
+
+ if (alloc_area->aa_free_structs_in_chunk > 0) {
+ break; /* found a free entry! */
+ }
+
+ }
+
+ if (alloc_area != NULL) {
+ alloc_area->aa_free_structs_in_chunk--;
+
+ if (alloc_area->aa_free_list != NULL) {
+ ret_mem = alloc_area->aa_free_list;
+
+ /*
+ Update the free list. The initial part of the struct is
+ used to hold a pointer to the next struct on the free
+ list. In this way, the free list chain is maintained at
+ 0 memory cost. */
+ alloc_area->aa_free_list =
+ ((Dwarf_Free_List) ret_mem)->fl_next;
+ } else if (alloc_area->aa_blob_start < alloc_area->aa_blob_end) {
+ ret_mem = alloc_area->aa_blob_start;
+
+ /*
+ Store pointer to chunk this struct belongs to in the
+ first few bytes. Return pointer to bytes after this
+ pointer storage. */
+ *(Dwarf_Alloc_Area *) ret_mem = alloc_area;
+ ret_mem += DW_RESERVE;
+
+ alloc_area->aa_blob_start += alloc_hdr->ah_bytes_one_struct;
+ } else {
+ /* else fall thru , though it should be impossible to fall
+ thru. And represents a disastrous programming error if
+ we get here. */
+#ifdef DEBUG
+ fprintf(stderr, "libdwarf Internal error start %x end %x\n",
+ (int) alloc_area->aa_blob_start,
+ (int) alloc_area->aa_blob_end);
+#endif
+ }
+ }
+
+ /* New memory has to malloc'ed since there are no free structs. */
+ if (ret_mem == 0) {
+ Dwarf_Word rounded_area_hdr_size;
+
+ alloc_hdr->ah_chunks_allocated++;
+
+ { /* this nonsense avoids a warning */
+ /* CONSTCOND would be better */
+ unsigned long v = sizeof(struct Dwarf_Alloc_Area_s);
+
+ rounded_area_hdr_size = ROUND_SIZE(v);
+ }
+
+ /*
+ Allocate memory to contain the required number of structs
+ and the Dwarf_Alloc_Area_s to control it. */
+ mem_block_size = alloc_hdr->ah_bytes_malloc_per_chunk +
+ rounded_area_hdr_size;
+
+ mem_block = malloc(mem_block_size);
+ if (mem_block == NULL) {
+ return (NULL);
+ }
+
+
+ /*
+ Attach the Dwarf_Alloc_Area_s struct to the list of chunks
+ malloc'ed for this struct type. Also initialize the fields
+ of the Dwarf_Alloc_Area_s. */
+ alloc_area = (Dwarf_Alloc_Area) mem_block;
+ alloc_area->aa_prev = 0;
+ if (alloc_hdr->ah_alloc_area_head != NULL) {
+ alloc_hdr->ah_alloc_area_head->aa_prev = alloc_area;
+ }
+ alloc_area->aa_free_list = 0;
+ alloc_area->aa_next = alloc_hdr->ah_alloc_area_head;
+ alloc_hdr->ah_alloc_area_head = alloc_area;
+
+ alloc_area->aa_alloc_hdr = alloc_hdr;
+ alloc_area->aa_free_structs_in_chunk =
+ (Dwarf_Sword) alloc_hdr->ah_structs_per_chunk - 1;
+ if (alloc_area->aa_free_structs_in_chunk < 1) {
+ /* If we get here, there is a disastrous programming error
+ somewhere. */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: free structs in chunk %d\n",
+ (int) alloc_area->aa_free_structs_in_chunk);
+#endif
+ return NULL;
+ }
+
+ /*
+ The struct returned begins immediately after the
+ Dwarf_Alloc_Area_s struct. */
+ ret_mem = mem_block + rounded_area_hdr_size;
+ alloc_area->aa_blob_start =
+ ret_mem + alloc_hdr->ah_bytes_one_struct;
+ alloc_area->aa_blob_end = mem_block + mem_block_size;
+
+ /*
+ Store pointer to chunk this struct belongs to in the first
+ few bytes. Return pointer to bytes after this pointer
+ storage. */
+ *(Dwarf_Alloc_Area *) ret_mem = alloc_area;
+ ret_mem += DW_RESERVE;
+ }
+
+ alloc_hdr->ah_last_alloc_area = alloc_area;
+ alloc_hdr->ah_struct_user_holds++;
+ memset(ret_mem, 0, alloc_hdr->ah_bytes_one_struct - DW_RESERVE);
+ return (ret_mem);
+}
+
+#endif /* ndef DWARF_SIMPLE_MALLOC */
+
+/*
+ This function returns a pointer to a region
+ of memory. For alloc_types that are not
+ strings or lists of pointers, only 1 struct
+ can be requested at a time. This is indicated
+ by an input count of 1. For strings, count
+ equals the length of the string it will
+ contain, i.e it the length of the string
+ plus 1 for the terminating null. For lists
+ of pointers, count is equal to the number of
+ pointers. For DW_DLA_FRAME_BLOCK, DW_DLA_RANGES, and
+ DW_DLA_LOC_BLOCK allocation types also, count
+ is the count of the number of structs needed.
+
+ This function cannot be used to allocate a
+ Dwarf_Debug_s struct.
+
+*/
+Dwarf_Ptr
+_dwarf_get_alloc(Dwarf_Debug dbg,
+ Dwarf_Small alloc_type, Dwarf_Unsigned count)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+
+ Dwarf_Ptr ret_mem;
+
+ Dwarf_Signed size = 0;
+ unsigned int index;
+ unsigned int type = alloc_type;
+
+ if (dbg == NULL) {
+ return (NULL);
+ }
+
+ if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
+ /* internal error */
+ return NULL;
+ }
+ index = index_into_allocated[type].ia_al_num;
+ /* zero also illegal but not tested for */
+
+ /* If the Dwarf_Debug is not fully set up, we will get index 0 for
+ any type and must do something. 'Not fully set up' can only
+ happen for DW_DLA_ERROR, I (davea) believe, and for that we call
+ special code here.. */
+
+ if (index == 0) {
+ if (alloc_type == DW_DLA_STRING) {
+ size = count;
+ } else if (alloc_type == DW_DLA_LIST) {
+ size = count * sizeof(Dwarf_Ptr);
+ } else if (alloc_type == DW_DLA_FRAME_BLOCK) {
+ size = count * sizeof(Dwarf_Frame_Op);
+ } else if (alloc_type == DW_DLA_LOC_BLOCK) {
+ size = count * sizeof(Dwarf_Loc);
+ } else if (alloc_type == DW_DLA_HASH_TABLE_ENTRY) {
+ size = count * sizeof(struct Dwarf_Hash_Table_Entry_s);
+ } else if (alloc_type == DW_DLA_ADDR) {
+ size = count *
+ (sizeof(Dwarf_Addr) > sizeof(Dwarf_Off) ?
+ sizeof(Dwarf_Addr) : sizeof(Dwarf_Off));
+ } else if (alloc_type == DW_DLA_RANGES) {
+ size = count * sizeof(Dwarf_Ranges);
+ } else if (alloc_type == DW_DLA_ERROR) {
+ void *m = _dwarf_special_no_dbg_error_malloc();
+
+ dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR);
+ return m;
+
+ } else {
+ /* If we get here, there is a disastrous programming error
+ somewhere. */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: type %d unexpected\n",
+ (int) type);
+#endif
+ }
+ } else {
+ alloc_hdr = &dbg->de_alloc_hdr[index];
+ if (alloc_hdr->ah_bytes_one_struct > 0) {
+#ifdef DWARF_SIMPLE_MALLOC
+ size = alloc_hdr->ah_bytes_one_struct;
+#else
+ {
+ void *m = _dwarf_find_memory(alloc_hdr);
+
+ dwarf_malloc_check_alloc_data(m, type);
+ if (index_into_allocated[type].specialconstructor) {
+ int res =
+ index_into_allocated[type].
+ specialconstructor(dbg, m);
+ if (res != DW_DLV_OK) {
+ /* We leak what we allocated in
+ _dwarf_find_memory when constructor fails. */
+ return NULL;
+ }
+ }
+ return m;
+ }
+#endif
+
+ } else {
+ /* Special case: should not really happen at all. */
+ if (type == DW_DLA_ERROR) {
+ /* dwarf_init failure. Because dbg is incomplete we
+ won't use it to record the malloc. */
+ void *m = _dwarf_special_no_dbg_error_malloc();
+
+ dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR);
+ return m;
+ } else {
+ /* If we get here, there is a disastrous programming
+ error somewhere. */
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_botch(3);
+#endif
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: Type %d unexpected\n",
+ (int) type);
+#endif
+ }
+ }
+ }
+
+ ret_mem = malloc(size);
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_add_to_list(dbg, ret_mem, (unsigned long) size,
+ type);
+#endif
+ if (ret_mem != NULL)
+ memset(ret_mem, 0, size);
+
+ dwarf_malloc_check_alloc_data(ret_mem, type);
+ if (index_into_allocated[type].specialconstructor) {
+ int res =
+ index_into_allocated[type].specialconstructor(dbg, ret_mem);
+ if (res != DW_DLV_OK) {
+ /* We leak what we allocated in _dwarf_find_memory when
+ constructor fails. */
+ return NULL;
+ }
+ }
+
+ return (ret_mem);
+}
+
+
+
+/*
+ This function is used to deallocate a region of memory
+ that was obtained by a call to _dwarf_get_alloc. Note
+ that though dwarf_dealloc() is a public function,
+ _dwarf_get_alloc() isn't.
+
+ For lists, typically arrays of pointers, it is assumed
+ that the space was allocated by a direct call to malloc,
+ and so a straight free() is done. This is also the case
+ for variable length blocks such as DW_DLA_FRAME_BLOCK
+ and DW_DLA_LOC_BLOCK and DW_DLA_RANGES.
+
+ For strings, the pointer might point to a string in
+ .debug_info or .debug_string. After this is checked,
+ and if found not to be the case, a free() is done,
+ again on the assumption that a malloc was used to
+ obtain the space.
+
+ For other types of structs, a pointer to the chunk that
+ the struct was allocated out of, is present in the bytes
+ preceding the pointer passed in. For this chunk it is
+ checked whether all the structs in that chunk are now free.
+ If so, the entire chunk is free_ed. Otherwise, the space
+ is added to the free list for that chunk, and the free count
+ incremented.
+
+ This function does not return anything.
+*/
+void
+dwarf_dealloc(Dwarf_Debug dbg,
+ Dwarf_Ptr space, Dwarf_Unsigned alloc_type)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Alloc_Area alloc_area;
+ unsigned int type = alloc_type;
+ unsigned int index;
+
+ if (space == NULL) {
+ return;
+ }
+ if (type == DW_DLA_ERROR) {
+ /* Get pointer to Dwarf_Alloc_Area this struct came from. See
+ dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */
+ alloc_area =
+ *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE);
+ if (alloc_area == 0) {
+ /* This is the special case of a failed dwarf_init(). Also
+ (and more signficantly) there are a variety of other
+ situations where libdwarf does not *know* what dbg is
+ involved (because of a libdwarf-caller-error) so
+ libdwarf uses NULL as the dbg. Those too wind up here. */
+ _dwarf_free_special_error(space);
+ dwarf_malloc_check_dealloc_data(space, type);
+ return;
+ }
+
+ }
+ if (dbg == NULL) {
+ /* App error, or an app that failed to succeed in a
+ dwarf_init() call. */
+ return;
+ }
+ if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
+ /* internal or user app error */
+ return;
+ }
+
+ index = index_into_allocated[type].ia_al_num;
+ /*
+ A string pointer may point into .debug_info or .debug_string.
+ Otherwise, they are directly malloc'ed. */
+ dwarf_malloc_check_dealloc_data(space, type);
+ if (index == 0) {
+ if (type == DW_DLA_STRING) {
+ if ((Dwarf_Small *) space >= dbg->de_debug_info.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_info.dss_data + dbg->de_debug_info.dss_size)
+ return;
+
+ if (dbg->de_debug_line.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_line.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_line.dss_data + dbg->de_debug_line.dss_size)
+ return;
+
+ if (dbg->de_debug_pubnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_pubnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_pubnames.dss_data +
+ dbg->de_debug_pubnames.dss_size)
+ return;
+
+ if (dbg->de_debug_frame.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_frame.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_frame.dss_data + dbg->de_debug_frame.dss_size)
+ return;
+
+ if (dbg->de_debug_str.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_str.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_str.dss_data + dbg->de_debug_str.dss_size)
+ return;
+
+ if (dbg->de_debug_funcnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_funcnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_funcnames.dss_data +
+ dbg->de_debug_funcnames.dss_size)
+ return;
+
+ if (dbg->de_debug_typenames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_typenames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_typenames.dss_data +
+ dbg->de_debug_typenames.dss_size)
+ return;
+ if (dbg->de_debug_pubtypes.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_pubtypes.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_pubtypes.dss_data +
+ dbg->de_debug_pubtypes.dss_size)
+ return;
+
+ if (dbg->de_debug_varnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_varnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_varnames.dss_data +
+ dbg->de_debug_varnames.dss_size)
+ return;
+
+ if (dbg->de_debug_weaknames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_weaknames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_weaknames.dss_data +
+ dbg->de_debug_weaknames.dss_size)
+ return;
+
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+#endif
+ free(space);
+ return;
+ }
+
+ if (type == DW_DLA_LIST ||
+ type == DW_DLA_FRAME_BLOCK ||
+ type == DW_DLA_LOC_BLOCK || type == DW_DLA_ADDR ||
+ type == DW_DLA_RANGES ||
+ type == DW_DLA_HASH_TABLE_ENTRY) {
+
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+#endif
+ free(space);
+ return;
+ }
+ /* else is an alloc type that is not used */
+ /* app or internal error */
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_botch(4);
+#endif
+ return;
+
+ }
+ if (index_into_allocated[type].specialdestructor) {
+ index_into_allocated[type].specialdestructor(space);
+ }
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+ free(space);
+#else /* !DWARF_SIMPLE_MALLOC */
+ alloc_hdr = &dbg->de_alloc_hdr[index];
+
+ /* Get pointer to Dwarf_Alloc_Area this struct came from. See
+ dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */
+ alloc_area = *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE);
+
+ /* ASSERT: alloc_area != NULL If NULL we could abort, let it
+ coredump below, or return, pretending all is well. We go on,
+ letting program crash. Is caller error. */
+
+ /*
+ Check that the alloc_hdr field of the alloc_area we have is
+ pointing to the right alloc_hdr. This is used to catch use of
+ incorrect deallocation code by the user. */
+ if (alloc_area->aa_alloc_hdr != alloc_hdr) {
+ /* If we get here, the user has called dwarf_dealloc wrongly or
+ there is some other disastrous error. By leaking mem here we
+ try to be safe... */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: type %d hdr mismatch %lx %lx "
+ "area ptr %lx\n",
+ (int) type,
+ (long) alloc_area->aa_alloc_hdr,
+ (long) alloc_hdr, (long) alloc_area);
+#endif
+ return;
+ }
+
+ alloc_hdr->ah_struct_user_holds--;
+ alloc_area->aa_free_structs_in_chunk++;
+
+ /*
+ Give chunk back to malloc only when every struct is freed */
+ if (alloc_area->aa_free_structs_in_chunk ==
+ alloc_hdr->ah_structs_per_chunk) {
+ if (alloc_area->aa_prev != NULL) {
+ alloc_area->aa_prev->aa_next = alloc_area->aa_next;
+ } else {
+ alloc_hdr->ah_alloc_area_head = alloc_area->aa_next;
+ }
+
+ if (alloc_area->aa_next != NULL) {
+ alloc_area->aa_next->aa_prev = alloc_area->aa_prev;
+ }
+
+ alloc_hdr->ah_chunks_allocated--;
+
+ if (alloc_area == alloc_hdr->ah_last_alloc_area) {
+ alloc_hdr->ah_last_alloc_area = NULL;
+ }
+ memset(alloc_area, 0, sizeof(*alloc_area));
+ free(alloc_area);
+ }
+
+ else {
+ ((Dwarf_Free_List) space)->fl_next = alloc_area->aa_free_list;
+ alloc_area->aa_free_list = space;
+ }
+#endif /* !DWARF_SIMPLE_MALLOC */
+}
+
+
+/*
+ Allocates space for a Dwarf_Debug_s struct,
+ since one does not exist.
+*/
+Dwarf_Debug
+_dwarf_get_debug(void
+ )
+{
+ Dwarf_Debug dbg;
+
+ dbg = (Dwarf_Debug) malloc(sizeof(struct Dwarf_Debug_s));
+ if (dbg == NULL)
+ return (NULL);
+ else
+ memset(dbg, 0, sizeof(struct Dwarf_Debug_s));
+ return (dbg);
+}
+
+
+/*
+ Sets up the Dwarf_Debug_s struct for all the
+ allocation types currently defined.
+ Allocation types DW_DLA_STRING, DW_DLA_LIST,
+ DW_DLA_FRAME_BLOCK, DW_DLA_LOC_BLOCK, DW_DLA_RANGES are
+ malloc'ed directly.
+
+ This routine should be called after _dwarf_setup(),
+ so that information about the sizes of the Dwarf
+ sections can be used to decide the number of
+ structs of each type malloc'ed.
+
+ Also DW_DLA_ELLIST, DW_DLA_BOUNDS, DW_DLA_TYPE,
+ DW_DLA_SUBSCR, DW_DLA_LINEBUF allocation types
+ are currently not used.
+ The ah_bytes_one_struct and ah_structs_per_chunk fields for
+ these types have been set to 1 for efficiency
+ in dwarf_get_alloc().
+
+ Ah_alloc_num should be greater than 1 for all
+ types that are currently being used.
+
+ Therefore, for these allocation types the
+ ah_bytes_one_struct, and ah_structs_per_chunk fields do not
+ need to be initialized.
+
+ Being an internal routine, assume proper dbg.
+*/
+
+Dwarf_Debug
+_dwarf_setup_debug(Dwarf_Debug dbg)
+{
+ int i;
+
+ for (i = 1; i <= MAX_DW_DLA; i++) {
+ const struct ial_s *ialp = &index_into_allocated[i];
+ unsigned int hdr_index = ialp->ia_al_num;
+ Dwarf_Word str_size = ialp->ia_struct_size;
+ Dwarf_Word str_count = ialp->ia_base_count;
+ Dwarf_Word rnded_size = ROUND_SIZE_WITH_POINTER(str_size);
+
+ Dwarf_Alloc_Hdr alloc_hdr = &dbg->de_alloc_hdr[hdr_index];
+
+ alloc_hdr->ah_bytes_one_struct = (Dwarf_Half) rnded_size;
+
+ /* ah_structs_per_chunk must be >0 else we are in trouble */
+ alloc_hdr->ah_structs_per_chunk = str_count;
+ alloc_hdr->ah_bytes_malloc_per_chunk = rnded_size * str_count;
+ }
+ return (dbg);
+}
+
+/*
+ This function prints out the statistics
+ collected on allocation of memory chunks.
+*/
+void
+dwarf_print_memory_stats(Dwarf_Debug dbg)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Shalf i;
+
+ /*
+ Alloc types start at 1, not 0. Hence, the first NULL string, and
+ also a size of MAX_DW_DLA + 1. */
+ char *alloc_type_name[MAX_DW_DLA + 1] = {
+ "",
+ "DW_DLA_STRING",
+ "DW_DLA_LOC",
+ "DW_DLA_LOCDESC",
+ "DW_DLA_ELLIST",
+ "DW_DLA_BOUNDS",
+ "DW_DLA_BLOCK",
+ "DW_DLA_DEBUG",
+ "DW_DLA_DIE",
+ "DW_DLA_LINE",
+ "DW_DLA_ATTR",
+ "DW_DLA_TYPE",
+ "DW_DLA_SUBSCR",
+ "DW_DLA_GLOBAL",
+ "DW_DLA_ERROR",
+ "DW_DLA_LIST",
+ "DW_DLA_LINEBUF",
+ "DW_DLA_ARANGE",
+ "DW_DLA_ABBREV",
+ "DW_DLA_FRAME_OP",
+ "DW_DLA_CIE",
+ "DW_DLA_FDE",
+ "DW_DLA_LOC_BLOCK",
+ "DW_DLA_FRAME_BLOCK",
+ "DW_DLA_FUNC",
+ "DW_DLA_TYPENAME",
+ "DW_DLA_VAR",
+ "DW_DLA_WEAK",
+ "DW_DLA_ADDR",
+ "DW_DLA_RANGES",
+ "DW_DLA_ABBREV_LIST",
+ "DW_DLA_CHAIN",
+ "DW_DLA_CU_CONTEXT",
+ "DW_DLA_FRAME",
+ "DW_DLA_GLOBAL_CONTEXT",
+ "DW_DLA_FILE_ENTRY",
+ "DW_DLA_LINE_CONTEXT",
+ "DW_DLA_LOC_CHAIN",
+ "DW_DLA_HASH_TABLE",
+ "DW_DLA_FUNC_CONTEXT",
+ "DW_DLA_TYPENAME_CONTEXT",
+ "DW_DLA_VAR_CONTEXT",
+ "DW_DLA_WEAK_CONTEXT",
+ "DW_DLA_PUBTYPES_CONTEXT",
+ "DW_DLA_HASH_TABLE_ENTRY",
+ };
+
+ if (dbg == NULL)
+ return;
+
+ printf("Size of Dwarf_Debug %4ld bytes\n",
+ (long) sizeof(*dbg));
+ printf("Size of Dwarf_Alloc_Hdr_s %4ld bytes\n",
+ (long) sizeof(struct Dwarf_Alloc_Hdr_s));
+ printf("size of Dwarf_Alloc_Area_s %4ld bytes\n",
+ (long) sizeof(struct Dwarf_Alloc_Area_s));
+
+ printf(" Alloc Type Curr Structs byt str\n");
+ printf(" ---------- ---- ------- per per\n");
+ for (i = 1; i <= MAX_DW_DLA; i++) {
+ int indx = index_into_allocated[i].ia_al_num;
+
+ alloc_hdr = &dbg->de_alloc_hdr[indx];
+ if (alloc_hdr->ah_bytes_one_struct != 1) {
+ printf("%2d %-25s %6d %8d %6d %6d\n",
+ (int) i,
+ alloc_type_name[i],
+ (int) alloc_hdr->ah_chunks_allocated,
+ (int) alloc_hdr->ah_struct_user_holds,
+ (int) alloc_hdr->ah_bytes_malloc_per_chunk,
+ (int) alloc_hdr->ah_structs_per_chunk);
+ }
+ }
+}
+
+
+#ifndef DWARF_SIMPLE_MALLOC
+/*
+ This recursively frees
+ the chunks still allocated, and
+ forward chained through the aa_next
+ pointer.
+*/
+static void
+_dwarf_recursive_free(Dwarf_Alloc_Area alloc_area)
+{
+ if (alloc_area->aa_next != NULL) {
+ _dwarf_recursive_free(alloc_area->aa_next);
+ }
+
+ alloc_area->aa_next = 0;
+ alloc_area->aa_prev = 0;
+ free(alloc_area);
+}
+#endif
+
+/* In the 'rela' relocation case we might have malloc'd
+ space to ensure it is read-write. In that case, free the space. */
+static void
+rela_free(struct Dwarf_Section_s * sec)
+{
+ if (sec->dss_data_was_malloc) {
+ free(sec->dss_data);
+ }
+ sec->dss_data = 0;
+ sec->dss_data_was_malloc = 0;
+}
+
+/*
+ Used to free all space allocated for this Dwarf_Debug.
+ The caller should assume that the Dwarf_Debug pointer
+ itself is no longer valid upon return from this function.
+
+ In case of difficulty, this function simply returns quietly.
+*/
+int
+_dwarf_free_all_of_one_debug(Dwarf_Debug dbg)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Shalf i;
+ Dwarf_CU_Context context = 0;
+ Dwarf_CU_Context nextcontext = 0;
+
+ if (dbg == NULL)
+ return (DW_DLV_ERROR);
+
+ /* To do complete validation that we have no surprising missing or
+ erroneous deallocs it is advisable to do the dwarf_deallocs here
+ that are not things the user can otherwise request.
+ Housecleaning. */
+
+ for (context = dbg->de_cu_context_list;
+ context; context = nextcontext) {
+ Dwarf_Hash_Table hash_table = context->cc_abbrev_hash_table;
+ _dwarf_free_abbrev_hash_table_contents(dbg,hash_table);
+ nextcontext = context->cc_next;
+ dwarf_dealloc(dbg, hash_table, DW_DLA_HASH_TABLE);
+ dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT);
+ }
+
+ /* Housecleaning done. Now really free all the space. */
+#ifdef DWARF_SIMPLE_MALLOC
+ if (dbg->de_simple_malloc_base) {
+ struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base;
+
+ while (smp) {
+ int i;
+ struct simple_malloc_record_s *prev_smp = 0;
+
+ for (i = 0; i < smp->sr_used; ++i) {
+ struct simple_malloc_entry_s *cur;
+
+ cur = &smp->sr_entry[i];
+ if (cur->se_addr != 0) {
+ free(cur->se_addr);
+ cur->se_addr = 0;
+ }
+ }
+ prev_smp = smp;
+ smp = smp->sr_next;
+ free(prev_smp);
+ }
+ dbg->de_simple_malloc_base = 0;
+ }
+#else
+ for (i = 1; i < ALLOC_AREA_REAL_TABLE_MAX; i++) {
+ int indx = i;
+
+ alloc_hdr = &dbg->de_alloc_hdr[indx];
+ if (alloc_hdr->ah_alloc_area_head != NULL) {
+ _dwarf_recursive_free(alloc_hdr->ah_alloc_area_head);
+ }
+ }
+
+#endif
+ rela_free(&dbg->de_debug_info);
+ rela_free(&dbg->de_debug_abbrev);
+ rela_free(&dbg->de_debug_line);
+ rela_free(&dbg->de_debug_loc);
+ rela_free(&dbg->de_debug_aranges);
+ rela_free(&dbg->de_debug_macinfo);
+ rela_free(&dbg->de_debug_pubnames);
+ rela_free(&dbg->de_debug_str);
+ rela_free(&dbg->de_debug_frame);
+ rela_free(&dbg->de_debug_frame_eh_gnu);
+ rela_free(&dbg->de_debug_pubtypes);
+ rela_free(&dbg->de_debug_funcnames);
+ rela_free(&dbg->de_debug_typenames);
+ rela_free(&dbg->de_debug_varnames);
+ rela_free(&dbg->de_debug_weaknames);
+ rela_free(&dbg->de_debug_ranges);
+ dwarf_harmless_cleanout(&dbg->de_harmless_errors);
+
+ memset(dbg, 0, sizeof(*dbg)); /* Prevent accidental use later. */
+ free(dbg);
+ return (DW_DLV_OK);
+}
+
+/* A special case: we have no dbg, no alloc header etc.
+ So create something out of thin air that we can recognize
+ in dwarf_dealloc.
+ Something with the prefix (prefix space hidden from caller).
+
+ Only applies to DW_DLA_ERROR, making up an error record.
+*/
+
+struct Dwarf_Error_s *
+_dwarf_special_no_dbg_error_malloc(void)
+{
+ /* the union unused things are to guarantee proper alignment */
+ union u {
+ Dwarf_Alloc_Area ptr_not_used;
+ struct Dwarf_Error_s base_not_used;
+ char data_space[sizeof(struct Dwarf_Error_s) +
+ (DW_RESERVE * 2)];
+ };
+ char *mem;
+
+ mem = malloc(sizeof(union u));
+
+ if (mem == 0) {
+ return 0;
+
+ }
+ memset(mem, 0, sizeof(union u));
+ mem += DW_RESERVE;
+ return (struct Dwarf_Error_s *) mem;
+}
+
+/* The free side of _dwarf_special_no_dbg_error_malloc()
+*/
+static void
+_dwarf_free_special_error(Dwarf_Ptr space)
+{
+ char *mem = (char *) space;
+
+ mem -= DW_RESERVE;
+ free(mem);
+}
+
+
+#ifdef DWARF_SIMPLE_MALLOC
+/* here solely for planting a breakpoint. */
+/* ARGSUSED */
+void
+_dwarf_simple_malloc_botch(int err)
+{
+ fprintf(stderr,"simple malloc botch %d\n",err);
+}
+static void
+_dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg,
+ Dwarf_Ptr addr,
+ unsigned long size, short alloc_type)
+{
+ struct simple_malloc_record_s *cur;
+ struct simple_malloc_entry_s *newentry;
+
+ if (!dbg->de_simple_malloc_base) {
+ /* First entry to this routine. */
+ dbg->de_simple_malloc_base =
+ malloc(sizeof(struct simple_malloc_record_s));
+ if (!dbg->de_simple_malloc_base) {
+ _dwarf_simple_malloc_botch(7);
+ return; /* no memory, give up */
+ }
+ memset(dbg->de_simple_malloc_base,
+ 0, sizeof(struct simple_malloc_record_s));
+ }
+ cur = dbg->de_simple_malloc_base;
+
+ if (cur->sr_used >= DSM_BLOCK_COUNT) {
+ /* Better not be > than as that means chaos */
+
+ /* Create a new block to link at the head. */
+
+ struct simple_malloc_record_s *newblock =
+ malloc(sizeof(struct simple_malloc_record_s));
+ if (!newblock) {
+ _dwarf_simple_malloc_botch(8);
+ return; /* Can do nothing, out of memory */
+ }
+ memset(newblock, 0, sizeof(struct simple_malloc_record_s));
+ /* Link the new block at the head of the chain, and make it
+ 'current' */
+ dbg->de_simple_malloc_base = newblock;
+ newblock->sr_next = cur;
+ cur = newblock;
+ }
+ newentry = &cur->sr_entry[cur->sr_used];
+ newentry->se_addr = addr;
+ newentry->se_size = size;
+ newentry->se_type = alloc_type;
+ ++cur->sr_used;
+}
+
+/*
+ DWARF_SIMPLE_MALLOC: testing the hypothesis that the existing
+ malloc scheme here (see _dwarf_get_alloc()) is pointless complexity.
+
+ DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing
+ tool to verify libdwarf malloc has no botches (though of course
+ such does not test the complicated standard-libdwarf-alloc code).
+
+ To properly answer the question, the simple-malloc allocate
+ and delete should be something other than a simple list.
+ Perhaps a heap, or perhaps a red-black tree.
+
+*/
+static void
+_dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg,
+ Dwarf_Ptr space, short alloc_type)
+{
+ if (space == 0) {
+ _dwarf_simple_malloc_botch(6);
+ }
+ if (dbg->de_simple_malloc_base) {
+ struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base;
+
+ while (smp) {
+ int i;
+
+ for (i = 0; i < smp->sr_used; ++i) {
+ struct simple_malloc_entry_s *cur;
+
+ cur = &smp->sr_entry[i];
+ if (cur->se_addr == space) {
+ if (cur->se_type != alloc_type) {
+ _dwarf_simple_malloc_botch(0);
+ }
+ cur->se_addr = 0;
+ return;
+ }
+ }
+ smp = smp->sr_next;
+ }
+ }
+ /* Never found the space. */
+ _dwarf_simple_malloc_botch(1);
+ return;
+
+}
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf_alloc.h b/usr/src/lib/libdwarf/common/dwarf_alloc.h
new file mode 100644
index 0000000000..3a61c692c6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_alloc.h
@@ -0,0 +1,177 @@
+/*
+
+ Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+/* #define DWARF_SIMPLE_MALLOC 1 */
+
+Dwarf_Ptr _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned);
+Dwarf_Debug _dwarf_get_debug(void);
+Dwarf_Debug _dwarf_setup_debug(Dwarf_Debug);
+int _dwarf_free_all_of_one_debug(Dwarf_Debug);
+
+typedef struct Dwarf_Alloc_Area_s *Dwarf_Alloc_Area;
+typedef struct Dwarf_Free_List_s *Dwarf_Free_List;
+
+/* ALLOC_AREA_INDEX_TABLE_MAX is the size of the
+ struct ial_s index_into_allocated array in dwarf_alloc.c
+*/
+#define ALLOC_AREA_INDEX_TABLE_MAX 45
+/* ALLOC_AREA_REAL_TABLE_MAX is the size of the array needed
+ to hold pointers to dwarf alloc chunk areas.
+ It's smaller as some of the index_into_allocated
+ entries (they look like {0,1,1,0,0} )
+ are treated specially and don't use 'chunks'.
+*/
+#define ALLOC_AREA_REAL_TABLE_MAX 32
+
+/*
+ This struct is used to chain all the deallocated
+ structs on the free list of each chain. The structs
+ are chained internally, by using the memory they
+ contain.
+*/
+struct Dwarf_Free_List_s {
+ Dwarf_Free_List fl_next;
+};
+
+
+/*
+ This struct is used to manage all the chunks malloc'ed
+ for a particular alloc_type. Many of the fields are
+ initialized by dwarf_init().
+*/
+struct Dwarf_Alloc_Hdr_s {
+
+ /* Count of actual number of structs user app holds pointers to
+ currently. */
+ Dwarf_Sword ah_struct_user_holds;
+
+ /*
+ Size of each struct that will be allocated for this alloc_type.
+ Initialized by dwarf_init(). */
+ Dwarf_Half ah_bytes_one_struct;
+
+ /*
+ Number of structs of this alloc_type that will be contained in
+ each chunk that is malloc'ed. Initialized by dwarf_init(). */
+ Dwarf_Word ah_structs_per_chunk;
+
+ /*
+ Number of bytes malloc'ed per chunk which is basically
+ (ah_bytes_one_struct+_DWARF_RESERVE) * ah_alloc_num. */
+ Dwarf_Word ah_bytes_malloc_per_chunk;
+
+ /* Count of chunks currently allocated for type. */
+ Dwarf_Sword ah_chunks_allocated;
+
+ /*
+ Points to a chain of Dwarf_Alloc_Area_s structs that represent
+ all the chunks currently allocated for the alloc_type. */
+ Dwarf_Alloc_Area ah_alloc_area_head;
+
+ /* Last Alloc Area that was allocated by malloc. The
+ free-space-search area looks here first and only if it is full
+ goes thru the list pointed to by ah_alloc_area_head. */
+ Dwarf_Alloc_Area ah_last_alloc_area;
+};
+
+
+/*
+ This struct is used to manage each chunk that is
+ malloc'ed for a particular alloc_type. For each
+ allocation type, the allocation header points to
+ a list of all the chunks malloc'ed for that type.
+*/
+struct Dwarf_Alloc_Area_s {
+
+ /* Points to the free list of structs in the chunk. */
+ Dwarf_Ptr aa_free_list;
+
+ /*
+ Count of the number of free structs in the chunk. This includes
+ both those on the free list, and in the blob. */
+ Dwarf_Sword aa_free_structs_in_chunk;
+
+ /*
+ Points to the first byte of the blob from which struct will be
+ allocated. A struct is put on the free_list only when it
+ dwarf_deallocated. Initial allocations are from the blob. */
+ Dwarf_Small *aa_blob_start;
+
+ /* Points just past the last byte of the blob. */
+ Dwarf_Small *aa_blob_end;
+
+ /* Points to alloc_hdr this alloc_area is linked to: The owner, in
+ other words. */
+ Dwarf_Alloc_Hdr aa_alloc_hdr;
+
+ /*
+ Used for chaining Dwarf_Alloc_Area_s atructs. Alloc areas are
+ doubly linked to enable deletion from the list in constant time. */
+ Dwarf_Alloc_Area aa_next;
+ Dwarf_Alloc_Area aa_prev;
+};
+
+struct Dwarf_Error_s *_dwarf_special_no_dbg_error_malloc(void);
+
+#ifdef DWARF_SIMPLE_MALLOC
+/*
+ DWARF_SIMPLE_MALLOC is for testing the hypothesis that the existing
+ complex malloc scheme in libdwarf is pointless complexity.
+
+ DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing
+ tool to verify libdwarf malloc has no botches (though of course
+ such does not test the complicated standard-libdwarf-alloc code).
+
+*/
+
+struct simple_malloc_entry_s {
+ Dwarf_Small *se_addr;
+ unsigned long se_size;
+ short se_type;
+};
+#define DSM_BLOCK_COUNT (1000)
+#define DSM_BLOCK_SIZE (sizeof(struct simple_malloc_entry_s)*DSM_BLOCK_COUNT)
+
+/* we do this so dwarf_dealloc can really free everything */
+struct simple_malloc_record_s {
+ struct simple_malloc_record_s *sr_next;
+ int sr_used;
+ struct simple_malloc_entry_s sr_entry[DSM_BLOCK_COUNT];
+};
+
+
+
+#endif /* DWARF_SIMPLE_MALLOC */
diff --git a/usr/src/lib/libdwarf/common/dwarf_arange.c b/usr/src/lib/libdwarf/common/dwarf_arange.c
new file mode 100644
index 0000000000..e7ad8acc5e
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_arange.c
@@ -0,0 +1,593 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_arange.h"
+#include "dwarf_global.h" /* for _dwarf_fixup_* */
+
+
+/* Common code for two user-visible routines to share.
+ Errors here result in memory leaks, but errors here
+ are serious (making aranges unusable) so we assume
+ callers will not repeat the error often or mind the leaks.
+*/
+static int
+dwarf_get_aranges_list(Dwarf_Debug dbg,
+ Dwarf_Chain * chain_out,
+ Dwarf_Signed * chain_count_out,
+ Dwarf_Error * error)
+{
+ /* Sweeps through the arange. */
+ Dwarf_Small *arange_ptr = 0;
+ Dwarf_Small *arange_ptr_start = 0;
+
+ /* Start of arange header. Used for rounding offset of arange_ptr
+ to twice the tuple size. Libdwarf requirement. */
+ Dwarf_Small *header_ptr = 0;
+
+ /* Version of .debug_aranges header. */
+ Dwarf_Half version = 0;
+
+ /* Offset of current set of aranges into .debug_info. */
+ Dwarf_Off info_offset = 0;
+
+ /* Size in bytes of addresses in target. */
+ Dwarf_Small address_size = 0;
+
+ /* Size in bytes of segment offsets in target. */
+ Dwarf_Small segment_size = 0;
+
+ /* Count of total number of aranges. */
+ Dwarf_Unsigned arange_count = 0;
+
+ Dwarf_Arange arange = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+
+ arange_ptr = dbg->de_debug_aranges.dss_data;
+ arange_ptr_start = arange_ptr;
+ do {
+ /* Length of current set of aranges. */
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small remainder = 0;
+ Dwarf_Small *arange_ptr_past_end = 0;
+ Dwarf_Unsigned range_entry_size = 0;
+
+ int local_length_size;
+
+ /*REFERENCED*/ /* Not used in this instance of the macro */
+ int local_extension_size = 0;
+
+ header_ptr = arange_ptr;
+
+ /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ arange_ptr, local_length_size,
+ local_extension_size);
+ arange_ptr_past_end = arange_ptr + length;
+
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ arange_ptr, sizeof(Dwarf_Half));
+ arange_ptr += sizeof(Dwarf_Half);
+ length = length - sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP) {
+ _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
+ arange_ptr, local_length_size);
+ arange_ptr += local_length_size;
+ length = length - local_length_size;
+ if (info_offset >= dbg->de_debug_info.dss_size) {
+ FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
+ "arange info offset.a");
+ if (info_offset >= dbg->de_debug_info.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+
+ address_size = *(Dwarf_Small *) arange_ptr;
+ /* It is not an error if the sizes differ.
+ Unusual, but not an error. */
+ arange_ptr = arange_ptr + sizeof(Dwarf_Small);
+ length = length - sizeof(Dwarf_Small);
+
+ segment_size = *(Dwarf_Small *) arange_ptr;
+ arange_ptr = arange_ptr + sizeof(Dwarf_Small);
+ length = length - sizeof(Dwarf_Small);
+ if (segment_size != 0) {
+ _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ range_entry_size = 2*address_size + segment_size;
+ /* Round arange_ptr offset to next multiple of address_size. */
+ remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
+ (range_entry_size);
+ if (remainder != 0) {
+ arange_ptr = arange_ptr + (2 * address_size) - remainder;
+ length = length - ((2 * address_size) - remainder);
+ }
+ do {
+ Dwarf_Addr range_address = 0;
+ Dwarf_Unsigned segment_selector = 0;
+ Dwarf_Unsigned range_length = 0;
+ /* For segmented address spaces, the first field to
+ read is a segment selector (new in DWARF4) */
+ if(version == 4 && segment_size != 0) {
+ READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned,
+ arange_ptr, segment_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+ }
+
+ READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
+ arange_ptr, address_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+
+ READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
+ arange_ptr, address_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+
+ { /* We used to suppress all-zero entries, but
+ now we return all aranges entries so we show
+ the entire content. March 31, 2010. */
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ arange->ar_segment_selector = segment_selector;
+ arange->ar_segment_selector_size = segment_size;
+ arange->ar_address = range_address;
+ arange->ar_length = range_length;
+ arange->ar_info_offset = info_offset;
+ arange->ar_dbg = dbg;
+ arange_count++;
+
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+ /* The current set of ranges is terminated by
+ range_address 0 and range_length 0, but that
+ does not necessarily terminate the ranges for this CU!
+ There can be multiple sets in that DWARF
+ does not explicitly forbid multiple sets.
+ DWARF2,3,4 section 7.20
+ We stop short to avoid overrun of the end of the CU.
+ */
+
+ } while (arange_ptr_past_end >= (arange_ptr + range_entry_size));
+
+ /* A compiler could emit some padding bytes here. dwarf2/3
+ (dwarf4 sec 7.20) does not clearly make extra padding
+ bytes illegal. */
+ if (arange_ptr_past_end < arange_ptr) {
+ char buf[200];
+ Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end;
+ Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
+ snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD."
+ " 0x%" DW_PR_DUx
+ " pad bytes at offset 0x%" DW_PR_DUx
+ " in .debug_aranges",
+ pad_count, offset);
+ dwarf_insert_harmless_error(dbg,buf);
+ }
+ /* For most compilers, arange_ptr == arange_ptr_past_end at
+ this point. But not if there were padding bytes */
+ arange_ptr = arange_ptr_past_end;
+ } while (arange_ptr <
+ dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);
+
+ if (arange_ptr !=
+ dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+ *chain_out = head_chain;
+ *chain_count_out = arange_count;
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns the count of the number of
+ aranges in the .debug_aranges section. It sets
+ aranges to point to a block of Dwarf_Arange's
+ describing the arange's. It returns DW_DLV_ERROR
+ on error.
+
+ Must be identical in most aspects to
+ dwarf_get_aranges_addr_offsets!
+
+*/
+int
+dwarf_get_aranges(Dwarf_Debug dbg,
+ Dwarf_Arange ** aranges,
+ Dwarf_Signed * returned_count, Dwarf_Error * error)
+{
+ /* Count of total number of aranges. */
+ Dwarf_Signed arange_count = 0;
+
+ Dwarf_Arange *arange_block = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Unsigned i = 0;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ arange_block = (Dwarf_Arange *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
+ if (arange_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ *(arange_block + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *aranges = arange_block;
+ *returned_count = (arange_count);
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns DW_DLV_OK if it succeeds
+ and DW_DLV_ERR or DW_DLV_OK otherwise.
+ count is set to the number of addresses in the
+ .debug_aranges section.
+ For each address, the corresponding element in
+ an array is set to the address itself(aranges) and
+ the section offset (offsets).
+ Must be identical in most aspects to
+ dwarf_get_aranges!
+*/
+int
+_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offsets,
+ Dwarf_Signed * count,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned i = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+
+ Dwarf_Signed arange_count = 0;
+ Dwarf_Addr *arange_addrs = 0;
+ Dwarf_Off *arange_offsets = 0;
+
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (error != NULL)
+ *error = NULL;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ arange_addrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_addrs == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange_offsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_offsets == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ Dwarf_Arange ar = curr_chain->ch_item;
+
+ arange_addrs[i] = ar->ar_address;
+ arange_offsets[i] = ar->ar_info_offset;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+ *count = arange_count;
+ *offsets = arange_offsets;
+ *addrs = arange_addrs;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function takes a pointer to a block
+ of Dwarf_Arange's, and a count of the
+ length of the block. It checks if the
+ given address is within the range of an
+ address range in the block. If yes, it
+ returns the appropriate Dwarf_Arange.
+ Otherwise, it returns DW_DLV_ERROR.
+*/
+int
+dwarf_get_arange(Dwarf_Arange * aranges,
+ Dwarf_Unsigned arange_count,
+ Dwarf_Addr address,
+ Dwarf_Arange * returned_arange, Dwarf_Error * error)
+{
+ Dwarf_Arange curr_arange = 0;
+ Dwarf_Unsigned i = 0;
+
+ if (aranges == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGES_NULL);
+ return (DW_DLV_ERROR);
+ }
+ for (i = 0; i < arange_count; i++) {
+ curr_arange = *(aranges + i);
+ if (address >= curr_arange->ar_address &&
+ address <
+ curr_arange->ar_address + curr_arange->ar_length) {
+ *returned_arange = curr_arange;
+ return (DW_DLV_OK);
+ }
+ }
+
+ return (DW_DLV_NO_ENTRY);
+}
+
+
+/*
+ This function takes an Dwarf_Arange,
+ and returns the offset of the first
+ die in the compilation-unit that the
+ arange belongs to. Returns DW_DLV_ERROR
+ on error.
+*/
+int
+dwarf_get_cu_die_offset(Dwarf_Arange arange,
+ Dwarf_Off * returned_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Off offset = 0;
+
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = arange->ar_dbg;
+ offset = arange->ar_info_offset;
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset);
+ return DW_DLV_OK;
+}
+
+/*
+ This function takes an Dwarf_Arange,
+ and returns the offset of the CU header
+ in the compilation-unit that the
+ arange belongs to. Returns DW_DLV_ERROR
+ on error.
+ Ensures .debug_info loaded so
+ the cu_offset is meaningful.
+*/
+int
+dwarf_get_arange_cu_header_offset(Dwarf_Arange arange,
+ Dwarf_Off * cu_header_offset_returned,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = arange->ar_dbg;
+ /* Like dwarf_get_arange_info this ensures debug_info loaded:
+ the cu_header is in debug_info and will be used else
+ we would not call dwarf_get_arange_cu_header_offset. */
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_header_offset_returned = arange->ar_info_offset;
+ return DW_DLV_OK;
+}
+
+
+
+
+/*
+ This function takes a Dwarf_Arange, and returns
+ true if it is not NULL. It also stores the start
+ address of the range in *start, the length of the
+ range in *length, and the offset of the first die
+ in the compilation-unit in *cu_die_offset. It
+ returns false on error.
+ If cu_die_offset returned ensures .debug_info loaded so
+ the cu_die_offset is meaningful.
+*/
+int
+dwarf_get_arange_info(Dwarf_Arange arange,
+ Dwarf_Addr * start,
+ Dwarf_Unsigned * length,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (start != NULL)
+ *start = arange->ar_address;
+ if (length != NULL)
+ *length = arange->ar_length;
+ if (cu_die_offset != NULL) {
+ Dwarf_Debug dbg = arange->ar_dbg;
+ Dwarf_Off offset = arange->ar_info_offset;
+
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_die_offset =
+ offset + _dwarf_length_of_cu_header(dbg, offset);
+ }
+ return (DW_DLV_OK);
+}
+
+
+/* New for DWARF4, entries may have segment information.
+ *segment is only meaningful if *segment_entry_size is non-zero. */
+int
+dwarf_get_arange_info_b(Dwarf_Arange arange,
+ Dwarf_Unsigned* segment,
+ Dwarf_Unsigned* segment_entry_size,
+ Dwarf_Addr * start,
+ Dwarf_Unsigned* length,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if(segment != NULL) {
+ *segment = arange->ar_segment_selector;
+ }
+ if(segment_entry_size != NULL) {
+ *segment_entry_size = arange->ar_segment_selector_size;
+ }
+ if (start != NULL)
+ *start = arange->ar_address;
+ if (length != NULL)
+ *length = arange->ar_length;
+ if (cu_die_offset != NULL) {
+ Dwarf_Debug dbg = arange->ar_dbg;
+ Dwarf_Off offset = arange->ar_info_offset;
+
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_die_offset =
+ offset + _dwarf_length_of_cu_header(dbg, offset);
+ }
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_arange.h b/usr/src/lib/libdwarf/common/dwarf_arange.h
new file mode 100644
index 0000000000..d6c537c452
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_arange.h
@@ -0,0 +1,71 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* This structure is used to read an arange into. */
+struct Dwarf_Arange_s {
+
+ /* The segment selector. Only non-zero if Dwarf4, only
+ meaningful if ar_segment_selector_size non-zero */
+ Dwarf_Unsigned ar_segment_selector;
+
+ /* Starting address of the arange, ie low-pc. */
+ Dwarf_Addr ar_address;
+
+ /* Length of the arange. */
+ Dwarf_Unsigned ar_length;
+
+
+ /*
+ Offset into .debug_info of the start of the compilation-unit
+ containing this set of aranges. */
+ Dwarf_Off ar_info_offset;
+
+ /* Corresponding Dwarf_Debug. */
+ Dwarf_Debug ar_dbg;
+
+ Dwarf_Half ar_segment_selector_size;
+};
+
+
+
+int
+ _dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offsets,
+ Dwarf_Signed * count,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/dwarf_base_types.h b/usr/src/lib/libdwarf/common/dwarf_base_types.h
new file mode 100644
index 0000000000..00e2700a81
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_base_types.h
@@ -0,0 +1,123 @@
+/*
+
+ Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "libdwarfdefs.h"
+
+#define true 1
+#define false 0
+
+/* to identify a cie */
+#define DW_CIE_ID ~(0x0)
+#define DW_CIE_VERSION 1 /* DWARF2 */
+#define DW_CIE_VERSION3 3 /* DWARF3 */
+#define DW_CIE_VERSION4 4 /* DWARF4 */
+
+#define DW_CU_VERSION2 2
+#define DW_CU_VERSION3 3
+#define DW_CU_VERSION4 4
+
+/* DWARF2,3 and 4 */
+#define DW_ARANGES_VERSION2 2
+
+#define DW_LINE_VERSION2 2
+#define DW_LINE_VERSION3 3
+#define DW_LINE_VERSION4 4
+
+
+/*
+ These are allocation type codes for structs that
+ are internal to the Libdwarf Consumer library.
+*/
+#define DW_DLA_ABBREV_LIST DW_DLA_RANGES + 1
+#define DW_DLA_CHAIN DW_DLA_RANGES + 2
+#define DW_DLA_CU_CONTEXT DW_DLA_RANGES + 3
+#define DW_DLA_FRAME DW_DLA_RANGES + 4
+#define DW_DLA_GLOBAL_CONTEXT DW_DLA_RANGES + 5
+#define DW_DLA_FILE_ENTRY DW_DLA_RANGES + 6
+#define DW_DLA_LINE_CONTEXT DW_DLA_RANGES + 7
+#define DW_DLA_LOC_CHAIN DW_DLA_RANGES + 8
+#define DW_DLA_HASH_TABLE DW_DLA_RANGES + 9
+#define DW_DLA_FUNC_CONTEXT DW_DLA_RANGES + 10
+#define DW_DLA_TYPENAME_CONTEXT DW_DLA_RANGES + 11
+#define DW_DLA_VAR_CONTEXT DW_DLA_RANGES + 12
+#define DW_DLA_WEAK_CONTEXT DW_DLA_RANGES + 13
+#define DW_DLA_PUBTYPES_CONTEXT DW_DLA_RANGES + 14 /* DWARF3 */
+#define DW_DLA_HASH_TABLE_ENTRY DW_DLA_RANGES + 15
+
+/* Maximum number of allocation types for allocation routines. */
+#define MAX_DW_DLA DW_DLA_HASH_TABLE_ENTRY
+
+/*Dwarf_Word is unsigned word usable for index, count in memory */
+/*Dwarf_Sword is signed word usable for index, count in memory */
+/* The are 32 or 64 bits depending if 64 bit longs or not, which
+** fits the ILP32 and LP64 models
+** These work equally well with ILP64.
+*/
+
+typedef unsigned long Dwarf_Word;
+typedef signed long Dwarf_Sword;
+
+typedef signed char Dwarf_Sbyte;
+typedef unsigned char Dwarf_Ubyte;
+typedef signed short Dwarf_Shalf;
+typedef Dwarf_Small *Dwarf_Byte_Ptr;
+
+/* these 2 are fixed sizes which must not vary with the
+** ILP32/LP64 model. Between these two, stay at 32 bit.
+*/
+typedef __uint32_t Dwarf_ufixed;
+typedef __int32_t Dwarf_sfixed;
+
+/*
+ In various places the code mistakenly associates
+ forms 8 bytes long with Dwarf_Signed or Dwarf_Unsigned
+ This is not a very portable assumption.
+ The following should be used instead for 64 bit integers.
+*/
+typedef __uint64_t Dwarf_ufixed64;
+typedef __int64_t Dwarf_sfixed64;
+
+
+typedef struct Dwarf_Abbrev_List_s *Dwarf_Abbrev_List;
+typedef struct Dwarf_File_Entry_s *Dwarf_File_Entry;
+typedef struct Dwarf_CU_Context_s *Dwarf_CU_Context;
+typedef struct Dwarf_Hash_Table_s *Dwarf_Hash_Table;
+typedef struct Dwarf_Hash_Table_Entry_s *Dwarf_Hash_Table_Entry;
+
+
+typedef struct Dwarf_Alloc_Hdr_s *Dwarf_Alloc_Hdr;
diff --git a/usr/src/lib/libdwarf/common/dwarf_die_deliv.c b/usr/src/lib/libdwarf/common/dwarf_die_deliv.c
new file mode 100644
index 0000000000..4ba9f2aded
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_die_deliv.c
@@ -0,0 +1,855 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+
+/*
+ For a given Dwarf_Debug dbg, this function checks
+ if a CU that includes the given offset has been read
+ or not. If yes, it returns the Dwarf_CU_Context
+ for the CU. Otherwise it returns NULL. Being an
+ internal routine, it is assumed that a valid dbg
+ is passed.
+
+ **This is a sequential search. May be too slow.
+
+ If debug_info and debug_abbrev not loaded, this will
+ wind up returning NULL. So no need to load before calling
+ this.
+*/
+static Dwarf_CU_Context
+_dwarf_find_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (offset >= dbg->de_info_last_offset)
+ return (NULL);
+
+ if (dbg->de_cu_context != NULL &&
+ dbg->de_cu_context->cc_next != NULL &&
+ dbg->de_cu_context->cc_next->cc_debug_info_offset == offset) {
+
+ return (dbg->de_cu_context->cc_next);
+ }
+
+ if (dbg->de_cu_context != NULL &&
+ dbg->de_cu_context->cc_debug_info_offset <= offset) {
+
+ for (cu_context = dbg->de_cu_context;
+ cu_context != NULL; cu_context = cu_context->cc_next) {
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size) {
+
+ return (cu_context);
+ }
+ }
+ }
+
+ for (cu_context = dbg->de_cu_context_list;
+ cu_context != NULL; cu_context = cu_context->cc_next) {
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size) {
+
+ return (cu_context);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/*
+ This routine checks the dwarf_offdie() list of
+ CU contexts for the right CU context.
+*/
+static Dwarf_CU_Context
+_dwarf_find_offdie_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ for (cu_context = dbg->de_offdie_cu_context;
+ cu_context != NULL; cu_context = cu_context->cc_next)
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size)
+
+ return (cu_context);
+
+ return (NULL);
+}
+
+
+/*
+ This function is used to create a CU Context for
+ a compilation-unit that begins at offset in
+ .debug_info. The CU Context is attached to the
+ list of CU Contexts for this dbg. It is assumed
+ that the CU at offset has not been read before,
+ and so do not call this routine before making
+ sure of this with _dwarf_find_CU_Context().
+ Returns NULL on error. As always, being an
+ internal routine, assumes a good dbg.
+
+ This function must always set a dwarf error code
+ before returning NULL. Always.
+*/
+static Dwarf_CU_Context
+_dwarf_make_CU_Context(Dwarf_Debug dbg,
+ Dwarf_Off offset, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Signed abbrev_offset = 0;
+ Dwarf_Byte_Ptr cu_ptr = 0;
+ int local_extension_size = 0;
+ int local_length_size = 0;
+
+ cu_context =
+ (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1);
+ if (cu_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+ cu_context->cc_dbg = dbg;
+
+ cu_ptr = (Dwarf_Byte_Ptr) (dbg->de_debug_info.dss_data + offset);
+
+ /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ cu_ptr, local_length_size, local_extension_size);
+ cu_context->cc_length_size = local_length_size;
+ cu_context->cc_extension_size = local_extension_size;
+
+
+ cu_context->cc_length = (Dwarf_Word) length;
+
+ READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half,
+ cu_ptr, sizeof(Dwarf_Half));
+ cu_ptr += sizeof(Dwarf_Half);
+
+ READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed,
+ cu_ptr, local_length_size);
+ cu_ptr += local_length_size;
+ cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset;
+
+ cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr;
+
+ if ((length < CU_VERSION_STAMP_SIZE + local_length_size +
+ CU_ADDRESS_SIZE_SIZE) ||
+ (offset + length + local_length_size +
+ local_extension_size > dbg->de_debug_info.dss_size)) {
+
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR);
+ return (NULL);
+ }
+
+ if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP
+ && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3
+ && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) {
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
+ return (NULL);
+ }
+
+ if (abbrev_offset >= dbg->de_debug_abbrev.dss_size) {
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR);
+ return (NULL);
+ }
+
+ cu_context->cc_abbrev_hash_table =
+ (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1);
+ if (cu_context->cc_abbrev_hash_table == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ cu_context->cc_debug_info_offset = (Dwarf_Word) offset;
+ dbg->de_info_last_offset =
+ (Dwarf_Word) (offset + length +
+ local_extension_size + local_length_size);
+
+ if (dbg->de_cu_context_list == NULL) {
+ dbg->de_cu_context_list = cu_context;
+ dbg->de_cu_context_list_end = cu_context;
+ } else {
+ dbg->de_cu_context_list_end->cc_next = cu_context;
+ dbg->de_cu_context_list_end = cu_context;
+ }
+
+ return (cu_context);
+}
+
+
+/*
+ Returns offset of next compilation-unit thru next_cu_offset
+ pointer.
+ It basically sequentially moves from one
+ cu to the next. The current cu is recorded
+ internally by libdwarf.
+
+ The _b form is new for DWARF4 adding new returned fields.
+*/
+int
+dwarf_next_cu_header(Dwarf_Debug dbg,
+ Dwarf_Unsigned * cu_header_length,
+ Dwarf_Half * version_stamp,
+ Dwarf_Unsigned * abbrev_offset,
+ Dwarf_Half * address_size,
+ Dwarf_Unsigned * next_cu_offset,
+ Dwarf_Error * error)
+{
+ return dwarf_next_cu_header_b(dbg,
+ cu_header_length,
+ version_stamp,
+ abbrev_offset,
+ address_size,
+ 0,0,
+ next_cu_offset,
+ error);
+}
+int
+dwarf_next_cu_header_b(Dwarf_Debug dbg,
+ Dwarf_Unsigned * cu_header_length,
+ Dwarf_Half * version_stamp,
+ Dwarf_Unsigned * abbrev_offset,
+ Dwarf_Half * address_size,
+ Dwarf_Half * offset_size,
+ Dwarf_Half * extension_size,
+ Dwarf_Unsigned * next_cu_offset,
+ Dwarf_Error * error)
+{
+ /* Offset for current and new CU. */
+ Dwarf_Unsigned new_offset = 0;
+
+ /* CU Context for current CU. */
+ Dwarf_CU_Context cu_context = 0;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /*
+ Get offset into .debug_info of next CU. If dbg has no context,
+ this has to be the first one. */
+ if (dbg->de_cu_context == NULL) {
+ new_offset = 0;
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ } else {
+ new_offset = dbg->de_cu_context->cc_debug_info_offset +
+ dbg->de_cu_context->cc_length +
+ dbg->de_cu_context->cc_length_size +
+ dbg->de_cu_context->cc_extension_size;
+ }
+
+ /*
+ Check that there is room in .debug_info beyond the new offset
+ for at least a new cu header. If not, return 0 to indicate end
+ of debug_info section, and reset de_cu_debug_info_offset to
+ enable looping back through the cu's. */
+ if ((new_offset + _dwarf_length_of_cu_header_simple(dbg)) >=
+ dbg->de_debug_info.dss_size) {
+ dbg->de_cu_context = NULL;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ /* Check if this CU has been read before. */
+ cu_context = _dwarf_find_CU_Context(dbg, new_offset);
+
+ /* If not, make CU Context for it. */
+ if (cu_context == NULL) {
+ cu_context = _dwarf_make_CU_Context(dbg, new_offset, error);
+ if (cu_context == NULL) {
+ /* Error if CU Context could not be made. Since
+ _dwarf_make_CU_Context has already registered an error
+ we do not do that here: we let the lower error pass
+ thru. */
+ return (DW_DLV_ERROR);
+ }
+ }
+
+ dbg->de_cu_context = cu_context;
+
+ if (cu_header_length != NULL)
+ *cu_header_length = cu_context->cc_length;
+
+ if (version_stamp != NULL)
+ *version_stamp = cu_context->cc_version_stamp;
+
+ if (abbrev_offset != NULL)
+ *abbrev_offset = cu_context->cc_abbrev_offset;
+
+ if (address_size != NULL)
+ *address_size = cu_context->cc_address_size;
+ if (offset_size != NULL)
+ *offset_size = cu_context->cc_length_size;
+ if (extension_size != NULL)
+ *extension_size = cu_context->cc_extension_size;
+
+ new_offset = new_offset + cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size;
+ *next_cu_offset = new_offset;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function does two slightly different things
+ depending on the input flag want_AT_sibling. If
+ this flag is true, it checks if the input die has
+ a DW_AT_sibling attribute. If it does it returns
+ a pointer to the start of the sibling die in the
+ .debug_info section. Otherwise it behaves the
+ same as the want_AT_sibling false case.
+
+ If the want_AT_sibling flag is false, it returns
+ a pointer to the immediately adjacent die in the
+ .debug_info section.
+
+ Die_info_end points to the end of the .debug_info
+ portion for the cu the die belongs to. It is used
+ to check that the search for the next die does not
+ cross the end of the current cu. Cu_info_start points
+ to the start of the .debug_info portion for the
+ current cu, and is used to add to the offset for
+ DW_AT_sibling attributes. Finally, has_die_child
+ is a pointer to a Dwarf_Bool that is set true if
+ the present die has children, false otherwise.
+ However, in case want_AT_child is true and the die
+ has a DW_AT_sibling attribute *has_die_child is set
+ false to indicate that the children are being skipped.
+
+ die_info_end points to the last byte+1 of the cu.
+
+*/
+static Dwarf_Byte_Ptr
+_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr,
+ Dwarf_CU_Context cu_context,
+ Dwarf_Byte_Ptr die_info_end,
+ Dwarf_Byte_Ptr cu_info_start,
+ Dwarf_Bool want_AT_sibling,
+ Dwarf_Bool * has_die_child)
+{
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Abbrev_List abbrev_list;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned utmp = 0;
+ Dwarf_Debug dbg = 0;
+
+ info_ptr = die_info_ptr;
+ DECODE_LEB128_UWORD(info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ return NULL;
+ }
+
+
+ abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
+ if (abbrev_list == NULL) {
+ return (NULL);
+ }
+ dbg = cu_context->cc_dbg;
+
+ *has_die_child = abbrev_list->ab_has_child;
+
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+ if (attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD updates info_ptr */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ attr_form = (Dwarf_Half) utmp6;
+
+ }
+
+ if (want_AT_sibling && attr == DW_AT_sibling) {
+ switch (attr_form) {
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) info_ptr;
+ break;
+ case DW_FORM_ref2:
+ /* READ_UNALIGNED does not update info_ptr */
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Half));
+ break;
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_ufixed));
+ break;
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Unsigned));
+ break;
+ case DW_FORM_ref_udata:
+ offset =
+ _dwarf_decode_u_leb128(info_ptr, &leb128_length);
+ break;
+ case DW_FORM_ref_addr:
+ /* Very unusual. The FORM is intended to refer to
+ a different CU, but a different CU cannot
+ be a sibling, can it?
+ We could ignore this and treat as if no DW_AT_sibling
+ present. Or derive the offset from it and if
+ it is in the same CU use it directly.
+ The offset here is *supposed* to be a global offset,
+ so adding cu_info_start is wrong to any offset
+ we find here unless cu_info_start
+ is zero! Lets pretend there is no DW_AT_sibling
+ attribute. */
+ goto no_sibling_attr;
+ default:
+ return (NULL);
+ }
+
+ /* Reset *has_die_child to indicate children skipped. */
+ *has_die_child = false;
+
+ /* A value beyond die_info_end indicates an error. Exactly
+ at die_info_end means 1-past-cu-end and simply means we
+ are at the end, do not return NULL. Higher level code
+ will detect that we are at the end. */
+ if (cu_info_start + offset > die_info_end) {
+ /* Error case, bad DWARF. */
+ return (NULL);
+ }
+ /* At or before end-of-cu */
+ return (cu_info_start + offset);
+ }
+
+ no_sibling_attr:
+ if (attr_form != 0) {
+ info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg,
+ attr_form,
+ cu_context->cc_address_size,
+ info_ptr,
+ cu_context->cc_length_size);
+ /* It is ok for info_ptr == die_info_end, as we will test
+ later before using a too-large info_ptr */
+ if (info_ptr > die_info_end) {
+ /* More than one-past-end indicates a bug somewhere,
+ likely bad dwarf generation. */
+ return (NULL);
+ }
+ }
+ } while (attr != 0 || attr_form != 0);
+
+ return (info_ptr);
+}
+
+
+/*
+ Given a Dwarf_Debug dbg, and a Dwarf_Die die, it returns
+ a Dwarf_Die for the sibling of die. In case die is NULL,
+ it returns (thru ptr) a Dwarf_Die for the first die in the current
+ cu in dbg. Returns DW_DLV_ERROR on error.
+
+ It is assumed that every sibling chain including those with
+ only one element is terminated with a NULL die, except a
+ chain with only a NULL die.
+
+ The algorithm moves from one die to the adjacent one. It
+ returns when the depth of children it sees equals the number
+ of sibling chain terminations. A single count, child_depth
+ is used to track the depth of children and sibling terminations
+ encountered. Child_depth is incremented when a die has the
+ Has-Child flag set unless the child happens to be a NULL die.
+ Child_depth is decremented when a die has Has-Child false,
+ and the adjacent die is NULL. Algorithm returns when
+ child_depth is 0.
+
+ **NOTE: Do not modify input die, since it is used at the end.
+*/
+int
+dwarf_siblingof(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Die * caller_ret_die, Dwarf_Error * error)
+{
+ Dwarf_Die ret_die = 0;
+ Dwarf_Byte_Ptr die_info_ptr = 0;
+ Dwarf_Byte_Ptr cu_info_start = 0;
+
+ /* die_info_end points 1-past end of die (once set) */
+ Dwarf_Byte_Ptr die_info_end = 0;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (die == NULL) {
+ /* Find root die of cu */
+ /* die_info_end is untouched here, need not be set in this
+ branch. */
+ Dwarf_Off off2;
+
+ /* If we've not loaded debug_info, de_cu_context will be NULL,
+ so no need to laod */
+
+ if (dbg->de_cu_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_DBG_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ off2 = dbg->de_cu_context->cc_debug_info_offset;
+ die_info_ptr = dbg->de_debug_info.dss_data +
+ off2 + _dwarf_length_of_cu_header(dbg, off2);
+ } else {
+ /* Find sibling die. */
+ Dwarf_Bool has_child = false;
+ Dwarf_Sword child_depth = 0;
+
+ /* We cannot have a legal die unless debug_info was loaded, so
+ no need to load debug_info here. */
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ die_info_ptr = die->di_debug_info_ptr;
+ if (*die_info_ptr == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ cu_info_start = dbg->de_debug_info.dss_data +
+ die->di_cu_context->cc_debug_info_offset;
+ die_info_end = cu_info_start + die->di_cu_context->cc_length +
+ die->di_cu_context->cc_length_size +
+ die->di_cu_context->cc_extension_size;
+
+ if ((*die_info_ptr) == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ child_depth = 0;
+ do {
+ die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr,
+ die->di_cu_context,
+ die_info_end,
+ cu_info_start, true,
+ &has_child);
+ if (die_info_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* die_info_end is one past end. Do not read it!
+ A test for ``!= die_info_end'' would work as well,
+ but perhaps < reads more like the meaning. */
+ if(die_info_ptr < die_info_end) {
+ if ((*die_info_ptr) == 0 && has_child) {
+ die_info_ptr++;
+ has_child = false;
+ }
+ }
+
+ /* die_info_ptr can be one-past-end. */
+ if ((die_info_ptr == die_info_end) ||
+ ((*die_info_ptr) == 0)) {
+ for (; child_depth > 0 && *die_info_ptr == 0;
+ child_depth--, die_info_ptr++);
+ } else {
+ child_depth = has_child ? child_depth + 1 : child_depth;
+ }
+
+ } while (child_depth != 0);
+ }
+
+ /* die_info_ptr > die_info_end is really a bug (possibly in dwarf
+ generation)(but we are past end, no more DIEs here), whereas
+ die_info_ptr == die_info_end means 'one past end, no more DIEs
+ here'. */
+ if (die != NULL && die_info_ptr >= die_info_end) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if ((*die_info_ptr) == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (ret_die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_die->di_debug_info_ptr = die_info_ptr;
+ ret_die->di_cu_context =
+ die == NULL ? dbg->de_cu_context : die->di_cu_context;
+
+ DECODE_LEB128_UWORD(die_info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ /* Zero means a null DIE */
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ return (DW_DLV_NO_ENTRY);
+ }
+ ret_die->di_abbrev_code = abbrev_code;
+ ret_die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(ret_die->di_cu_context, abbrev_code);
+ if (ret_die->di_abbrev_list == NULL || (die == NULL &&
+ ret_die->di_abbrev_list->
+ ab_tag !=
+ DW_TAG_compile_unit)) {
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU);
+ return (DW_DLV_ERROR);
+ }
+
+ *caller_ret_die = ret_die;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_child(Dwarf_Die die,
+ Dwarf_Die * caller_ret_die, Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr die_info_ptr = 0;
+
+ /* die_info_end points one-past-end of die area. */
+ Dwarf_Byte_Ptr die_info_end = 0;
+ Dwarf_Die ret_die = 0;
+ Dwarf_Bool has_die_child = 0;
+ Dwarf_Debug dbg;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+ die_info_ptr = die->di_debug_info_ptr;
+
+ /* NULL die has no child. */
+ if ((*die_info_ptr) == 0)
+ return (DW_DLV_NO_ENTRY);
+
+ die_info_end = dbg->de_debug_info.dss_data +
+ die->di_cu_context->cc_debug_info_offset +
+ die->di_cu_context->cc_length +
+ die->di_cu_context->cc_length_size +
+ die->di_cu_context->cc_extension_size;
+
+ die_info_ptr =
+ _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context,
+ die_info_end, NULL, false,
+ &has_die_child);
+ if (die_info_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (!has_die_child)
+ return (DW_DLV_NO_ENTRY);
+
+ ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (ret_die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ ret_die->di_debug_info_ptr = die_info_ptr;
+ ret_die->di_cu_context = die->di_cu_context;
+
+ DECODE_LEB128_UWORD(die_info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ /* We have arrived at a null DIE, at the end of a CU or the end
+ of a list of siblings. */
+ *caller_ret_die = 0;
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ return DW_DLV_NO_ENTRY;
+ }
+ ret_die->di_abbrev_code = abbrev_code;
+ ret_die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(die->di_cu_context, abbrev_code);
+ if (ret_die->di_abbrev_list == NULL) {
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ *caller_ret_die = ret_die;
+ return (DW_DLV_OK);
+}
+
+/*
+ Given a (global, not cu_relative) die offset, this returns
+ a pointer to a DIE thru *new_die.
+ It is up to the caller to do a
+ dwarf_dealloc(dbg,*new_die,DW_DLE_DIE);
+*/
+int
+dwarf_offdie(Dwarf_Debug dbg,
+ Dwarf_Off offset, Dwarf_Die * new_die, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Off new_cu_offset = 0;
+ Dwarf_Die die = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Unsigned abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = _dwarf_find_CU_Context(dbg, offset);
+ if (cu_context == NULL)
+ cu_context = _dwarf_find_offdie_CU_Context(dbg, offset);
+
+ if (cu_context == NULL) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ if (dbg->de_offdie_cu_context_end != NULL) {
+ Dwarf_CU_Context lcu_context =
+ dbg->de_offdie_cu_context_end;
+ new_cu_offset =
+ lcu_context->cc_debug_info_offset +
+ lcu_context->cc_length +
+ lcu_context->cc_length_size +
+ lcu_context->cc_extension_size;
+ }
+
+
+ do {
+ if ((new_cu_offset +
+ _dwarf_length_of_cu_header_simple(dbg)) >=
+ dbg->de_debug_info.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context =
+ _dwarf_make_CU_Context(dbg, new_cu_offset, error);
+ if (cu_context == NULL) {
+ /* Error if CU Context could not be made. Since
+ _dwarf_make_CU_Context has already registered an
+ error we do not do that here: we let the lower error
+ pass thru. */
+
+ return (DW_DLV_ERROR);
+ }
+
+ if (dbg->de_offdie_cu_context == NULL) {
+ dbg->de_offdie_cu_context = cu_context;
+ dbg->de_offdie_cu_context_end = cu_context;
+ } else {
+ dbg->de_offdie_cu_context_end->cc_next = cu_context;
+ dbg->de_offdie_cu_context_end = cu_context;
+ }
+
+ new_cu_offset = new_cu_offset + cu_context->cc_length +
+ cu_context->cc_length_size;
+
+ } while (offset >= new_cu_offset);
+ }
+
+ die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ die->di_cu_context = cu_context;
+
+ info_ptr = dbg->de_debug_info.dss_data + offset;
+ die->di_debug_info_ptr = info_ptr;
+ DECODE_LEB128_UWORD(info_ptr, utmp);
+ abbrev_code = utmp;
+ if (abbrev_code == 0) {
+ /* we are at a null DIE (or there is a bug). */
+ *new_die = 0;
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ return DW_DLV_NO_ENTRY;
+ }
+ die->di_abbrev_code = abbrev_code;
+ die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
+ if (die->di_abbrev_list == NULL) {
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *new_die = die;
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_die_deliv.h b/usr/src/lib/libdwarf/common/dwarf_die_deliv.h
new file mode 100644
index 0000000000..f1ecb153ba
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_die_deliv.h
@@ -0,0 +1,57 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+/*
+ This struct holds information about a abbreviation.
+ It is put in the hash table for abbreviations for
+ a compile-unit.
+*/
+struct Dwarf_Abbrev_List_s {
+
+ Dwarf_Unsigned ab_code;
+ Dwarf_Half ab_tag;
+ Dwarf_Half ab_has_child;
+
+ /*
+ Points to start of attribute and form pairs in the .debug_abbrev
+ section for the abbrev. */
+ Dwarf_Byte_Ptr ab_abbrev_ptr;
+
+ struct Dwarf_Abbrev_List_s *ab_next;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_elf_access.c b/usr/src/lib/libdwarf/common/dwarf_elf_access.c
new file mode 100644
index 0000000000..6caa64a758
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_elf_access.c
@@ -0,0 +1,976 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, Inc. All Rights Reserved.
+ Portions Copyright 2009-2010 David Anderson. All rights reserved.
+ Portions Copyright 2009-2010 Novell Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_elf_access.h"
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#ifdef HAVE_LIBELF_H
+#include <libelf.h>
+#else
+#ifdef HAVE_LIBELF_LIBELF_H
+#include <libelf/libelf.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef EM_MIPS
+/* This is the standard elf value EM_MIPS. */
+#define EM_MIPS 8
+#endif
+
+
+#ifdef HAVE_ELF64_GETEHDR
+extern Elf64_Ehdr *elf64_getehdr(Elf *);
+#endif
+#ifdef HAVE_ELF64_GETSHDR
+extern Elf64_Shdr *elf64_getshdr(Elf_Scn *);
+#endif
+#ifdef WORDS_BIGENDIAN
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word(dest, \
+ ((char *)source) +srclength-len_out, \
+ len_out) ; \
+ }
+
+
+#else /* LITTLE ENDIAN */
+
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word( (dest) , \
+ ((char *)source) , \
+ len_out) ; \
+ }
+#endif
+
+
+
+typedef struct {
+ dwarf_elf_handle elf;
+ int is_64bit;
+ Dwarf_Small length_size;
+ Dwarf_Small pointer_size;
+ Dwarf_Unsigned section_count;
+ Dwarf_Endianness endianness;
+ Dwarf_Small machine;
+ int libdwarf_owns_elf;
+ Elf32_Ehdr *ehdr32;
+
+#ifdef HAVE_ELF64_GETEHDR
+ Elf64_Ehdr *ehdr64;
+#endif
+ /* Elf symtab and its strtab. Initialized at first
+ call to do relocations, the actual data is in the Dwarf_Debug
+ struct, not allocated locally here. */
+ struct Dwarf_Section_s *symtab;
+ struct Dwarf_Section_s *strtab;
+
+} dwarf_elf_object_access_internals_t;
+
+struct Dwarf_Elf_Rela {
+ Dwarf_ufixed64 r_offset;
+ /*Dwarf_ufixed64 r_info; */
+ Dwarf_ufixed64 r_type;
+ Dwarf_ufixed64 r_symidx;
+ Dwarf_ufixed64 r_addend;
+};
+
+
+static int dwarf_elf_object_access_load_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Small** section_data,
+ int* error);
+
+/*
+ dwarf_elf_object_access_internals_init()
+ */
+static int
+dwarf_elf_object_access_internals_init(void* obj_in,
+ dwarf_elf_handle elf,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ char *ehdr_ident = 0;
+ Dwarf_Half machine = 0;
+ obj->elf = elf;
+
+ if ((ehdr_ident = elf_getident(elf, NULL)) == NULL) {
+ *error = DW_DLE_ELF_GETIDENT_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ obj->is_64bit = (ehdr_ident[EI_CLASS] == ELFCLASS64);
+
+
+ if(ehdr_ident[EI_DATA] == ELFDATA2LSB){
+ obj->endianness = DW_OBJECT_LSB;
+ }
+ else if(ehdr_ident[EI_DATA] == ELFDATA2MSB){
+ obj->endianness = DW_OBJECT_MSB;
+ }
+
+ if (obj->is_64bit) {
+#ifdef HAVE_ELF64_GETEHDR
+ obj->ehdr64 = elf64_getehdr(elf);
+ if (obj->ehdr64 == NULL) {
+ *error = DW_DLE_ELF_GETEHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ obj->section_count = obj->ehdr64->e_shnum;
+ machine = obj->ehdr64->e_machine;
+ obj->machine = machine;
+#else
+ *error = DW_DLE_NO_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif
+ }
+ else {
+ obj->ehdr32 = elf32_getehdr(elf);
+ if (obj->ehdr32 == NULL) {
+ *error = DW_DLE_ELF_GETEHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ obj->section_count = obj->ehdr32->e_shnum;
+ machine = obj->ehdr32->e_machine;
+ obj->machine = machine;
+ }
+
+ /* The following length_size is Not Too Significant. Only used
+ one calculation, and an approximate one at that. */
+ obj->length_size = obj->is_64bit ? 8 : 4;
+ obj->pointer_size = obj->is_64bit ? 8 : 4;
+
+ if (obj->is_64bit && machine != EM_MIPS) {
+ /* MIPS/IRIX makes pointer size and length size 8 for -64.
+ Other platforms make length 4 always. */
+ /* 4 here supports 32bit-offset dwarf2, as emitted by cygnus
+ tools, and the dwarfv2.1 64bit extension setting.
+ This is not the same as the size-of-an-offset, which
+ is 4 in 32bit dwarf and 8 in 64bit dwarf. */
+ obj->length_size = 4;
+ }
+ return DW_DLV_OK;
+}
+
+/*
+ dwarf_elf_object_access_get_byte_order
+ */
+static
+Dwarf_Endianness
+dwarf_elf_object_access_get_byte_order(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->endianness;
+}
+
+/*
+ dwarf_elf_object_access_get_section_count()
+ */
+static
+Dwarf_Unsigned
+dwarf_elf_object_access_get_section_count(void * obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->section_count;
+}
+
+
+/*
+ dwarf_elf_object_access_get_section()
+ */
+static
+int
+dwarf_elf_object_access_get_section_info(
+ void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Obj_Access_Section* ret_scn,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+
+ Elf32_Shdr *shdr32 = 0;
+
+#ifdef HAVE_ELF64_GETSHDR
+ Elf64_Shdr *shdr64 = 0;
+#endif
+ Elf_Scn *scn = 0;
+
+
+ scn = elf_getscn(obj->elf, section_index);
+ if (scn == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+ if (obj->is_64bit) {
+#ifdef HAVE_ELF64_GETSHDR
+ shdr64 = elf64_getshdr(scn);
+ if (shdr64 == NULL) {
+ *error = DW_DLE_ELF_GETSHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ ret_scn->size = shdr64->sh_size;
+ ret_scn->addr = shdr64->sh_addr;
+ ret_scn->link = shdr64->sh_link;
+
+ ret_scn->name = elf_strptr(obj->elf, obj->ehdr64->e_shstrndx,
+ shdr64->sh_name);
+ if(ret_scn->name == NULL) {
+ *error = DW_DLE_ELF_STRPTR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_OK;
+#else
+ *error = DW_DLE_MISSING_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif /* HAVE_ELF64_GETSHDR */
+ }
+ if ((shdr32 = elf32_getshdr(scn)) == NULL) {
+ *error = DW_DLE_ELF_GETSHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ ret_scn->size = shdr32->sh_size;
+ ret_scn->addr = shdr32->sh_addr;
+ ret_scn->link = shdr32->sh_link;
+
+ ret_scn->name = elf_strptr(obj->elf, obj->ehdr32->e_shstrndx,
+ shdr32->sh_name);
+ if (ret_scn->name == NULL) {
+ *error = DW_DLE_ELF_STRPTR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_OK;
+}
+
+/*
+ dwarf_elf_object_access_get_length_size
+ */
+static
+Dwarf_Small
+dwarf_elf_object_access_get_length_size(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->length_size;
+}
+
+/*
+ dwarf_elf_object_access_get_pointer_size
+ */
+static
+Dwarf_Small
+dwarf_elf_object_access_get_pointer_size(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->pointer_size;
+}
+
+#define MATCH_REL_SEC(i_,s_,r_) \
+if(i_ == s_.dss_index) { \
+ *r_ = &s_; \
+ return DW_DLV_OK; \
+}
+
+static int
+find_section_to_relocate(Dwarf_Debug dbg,Dwarf_Half section_index,
+ struct Dwarf_Section_s **relocatablesec, int *error)
+{
+ MATCH_REL_SEC(section_index,dbg->de_debug_info,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_abbrev,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_line,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_loc,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_aranges,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_macinfo,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_pubnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_ranges,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_frame,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_frame_eh_gnu,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_pubtypes,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_funcnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_typenames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_varnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_weaknames,relocatablesec);
+ /* dbg-> de_debug_str,syms); */
+ /* de_elf_symtab,syms); */
+ /* de_elf_strtab,syms); */
+ *error = DW_DLE_RELOC_SECTION_MISMATCH;
+ return DW_DLV_ERROR;
+
+}
+#undef MATCH_REL_SEC
+
+static void
+get_rela_elf32(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine, struct Dwarf_Elf_Rela *relap)
+{
+ Elf32_Rela *relp = (Elf32_Rela*)(data + (i * sizeof(Elf32_Rela)));
+ relap->r_offset = relp->r_offset;
+ /*
+ relap->r_info = relp->r_info;
+ */
+ relap->r_type = ELF32_R_TYPE(relp->r_info);
+ relap->r_symidx = ELF32_R_SYM(relp->r_info);
+ relap->r_addend = relp->r_addend;
+}
+
+static void
+get_rela_elf64(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine,struct Dwarf_Elf_Rela *relap)
+{
+#ifdef HAVE_ELF64_RELA
+ Elf64_Rela * relp = (Elf64_Rela*)(data + (i * sizeof(Elf64_Rela)));
+ relap->r_offset = relp->r_offset;
+ /*
+ relap->r_info = relp->r_info;
+ */
+ if(machine == EM_MIPS && endianness == DW_OBJECT_LSB ) {
+ /* This is really wierd. Treat this very specially.
+ The Elf64 LE MIPS object used for
+ testing (that has rela) wants the
+ values as sym ssym type3 type2 type, treating
+ each value as independent value. But libelf xlate
+ treats it as something else so we fudge here.
+ It is unclear
+ how to precisely characterize where these relocations
+ were used.
+ SGI MIPS on IRIX never used .rela relocations.
+ The BE 64bit elf MIPS test object with rela uses traditional
+ elf relocation layouts, not this special case. */
+#define ELF64MIPS_REL_SYM(i) ((i) & 0xffffffff)
+#define ELF64MIPS_REL_TYPE(i) ((i >> 56) &0xff)
+ /* We ignore the special TYPE2 and TYPE3, they should be
+ value R_MIPS_NONE in rela. */
+ relap->r_type = ELF64MIPS_REL_TYPE(relp->r_info);
+ relap->r_symidx = ELF64MIPS_REL_SYM(relp->r_info);
+#undef MIPS64SYM
+#undef MIPS64TYPE
+ } else
+ {
+ relap->r_type = ELF64_R_TYPE(relp->r_info);
+ relap->r_symidx = ELF64_R_SYM(relp->r_info);
+ }
+ relap->r_addend = relp->r_addend;
+#endif
+}
+
+static void
+get_relocations_array(Dwarf_Bool is_64bit,
+ int endianness,
+ int machine,
+ Dwarf_Small *data,
+ unsigned int num_relocations,
+ struct Dwarf_Elf_Rela *relap)
+{
+ unsigned int i = 0;
+ void (*get_relocations)(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine,
+ struct Dwarf_Elf_Rela *relap);
+
+ /* Handle 32/64 bit issue
+ */
+ if (is_64bit) {
+ get_relocations = get_rela_elf64;
+ } else {
+ get_relocations = get_rela_elf32;
+ }
+
+ for (i=0; i < num_relocations; i++) {
+ get_relocations(data, i,endianness,machine, &(relap[i]));
+ }
+
+}
+
+static int
+get_relocation_entries(Dwarf_Bool is_64bit,
+ int endianness,
+ int machine,
+ Dwarf_Small *relocation_section,
+ Dwarf_Unsigned relocation_section_size,
+ struct Dwarf_Elf_Rela **relas,
+ unsigned int *nrelas,
+ int *error)
+{
+ unsigned int relocation_size = 0;
+
+ if (is_64bit) {
+#ifdef HAVE_ELF64_RELA
+ relocation_size = sizeof(Elf64_Rela);
+#else
+ *error = DW_DLE_MISSING_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif
+ } else {
+ relocation_size = sizeof(Elf32_Rela);
+ }
+
+ if (relocation_section == NULL) {
+ *error = DW_DLE_RELOC_SECTION_PTR_NULL;
+ return(DW_DLV_ERROR);
+ }
+
+ if ((relocation_section_size != 0)) {
+ size_t bytescount = 0;
+ if(relocation_section_size%relocation_size) {
+ *error = DW_DLE_RELOC_SECTION_LENGTH_ODD;
+ return DW_DLV_ERROR;
+ }
+ *nrelas = relocation_section_size/relocation_size;
+ bytescount = (*nrelas) * sizeof(struct Dwarf_Elf_Rela);
+ *relas = malloc(bytescount);
+ if (!*relas) {
+ *error = DW_DLE_MAF;
+ return(DW_DLV_ERROR);
+ }
+ memset(*relas,0,bytescount);
+ get_relocations_array(is_64bit,endianness,machine, relocation_section,
+ *nrelas, *relas);
+ }
+ return(DW_DLV_OK);
+}
+
+static Dwarf_Bool
+is_32bit_abs_reloc(unsigned int type, Dwarf_Half machine)
+{
+ Dwarf_Bool r = 0;
+ switch (machine) {
+#if defined(EM_MIPS) && defined (R_MIPS_32)
+ case EM_MIPS:
+ r = (type == R_MIPS_32);
+ break;
+#endif
+#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA32)
+ case EM_SPARC32PLUS:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_SPARCV9) && defined (R_SPARC_UA32)
+ case EM_SPARCV9:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_SPARC) && defined (R_SPARC_UA32)
+ case EM_SPARC:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_386) && defined (R_386_32)
+ case EM_386:
+ r = (type == R_386_32);
+ break;
+#endif
+#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB)
+ case EM_IA_64:
+ r = (type == R_IA64_SECREL32LSB);
+ break;
+#endif
+#if defined(EM_PPC64) && defined (R_PPC64_ADDR32)
+ case EM_PPC64:
+ r = (type == R_PPC64_ADDR32);
+ break;
+#endif
+#if defined(EM_PPC) && defined (R_PPC_ADDR32)
+ case EM_PPC:
+ r = (type == R_PPC_ADDR32);
+ break;
+#endif
+#if defined(EM_S390) && defined (R_390_32)
+ case EM_S390:
+ r = (type == R_390_32);
+ break;
+#endif
+#if defined(EM_X86_64) && defined (R_X86_64_32)
+ case EM_X86_64:
+ r = (type == R_X86_64_32);
+ break;
+#endif
+ }
+ return r;
+}
+
+static Dwarf_Bool
+is_64bit_abs_reloc(unsigned int type, Dwarf_Half machine)
+{
+ Dwarf_Bool r = 0;
+ switch (machine) {
+#if defined(EM_MIPS) && defined (R_MIPS_64)
+ case EM_MIPS:
+ r = (type == R_MIPS_64);
+ break;
+#endif
+#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA64)
+ case EM_SPARC32PLUS:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_SPARCV9) && defined (R_SPARC_UA64)
+ case EM_SPARCV9:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_SPARC) && defined (R_SPARC_UA64)
+ case EM_SPARC:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB)
+ case EM_IA_64:
+ r = (type == R_IA64_DIR64LSB);
+ break;
+#endif
+#if defined(EM_PPC64) && defined (R_PPC64_ADDR64)
+ case EM_PPC64:
+ r = (type == R_PPC64_ADDR64);
+ break;
+#endif
+#if defined(EM_S390) && defined (R_390_64)
+ case EM_S390:
+ r = (type == R_390_64);
+ break;
+#endif
+#if defined(EM_X86_64) && defined (R_X86_64_64)
+ case EM_X86_64:
+ r = (type == R_X86_64_64);
+ break;
+#endif
+ }
+ return r;
+}
+
+
+static void
+update_entry(Dwarf_Debug dbg,
+ Dwarf_Bool is_64bit, Dwarf_Endianness endianess,
+ Dwarf_Half machine, struct Dwarf_Elf_Rela *rela,
+ Dwarf_Small *target_section, Dwarf_Small *section_data)
+{
+ unsigned int type = 0;
+ unsigned int sym_idx = 0;
+#ifdef HAVE_ELF64_SYM
+ Elf64_Sym sym_buf;
+ Elf64_Sym *sym = 0;
+#else
+ Elf32_Sym sym_buf;
+ Elf32_Sym *sym = 0;
+#endif
+ Elf32_Sym *sym32 = 0;
+ Dwarf_ufixed64 offset = 0;
+ Dwarf_sfixed64 addend = 0;
+ Dwarf_Unsigned reloc_size = 0;
+
+
+ /* Dwarf_Elf_Rela dereferencing */
+ offset = rela->r_offset;
+ addend = rela->r_addend;
+ type = rela->r_type;
+ sym_idx = rela->r_symidx;
+
+ if (is_64bit) {
+#ifdef HAVE_ELF64_SYM
+ sym = &((Elf64_Sym*)section_data)[sym_idx];
+#endif
+ } else {
+ sym32 = &((Elf32_Sym*)section_data)[sym_idx];
+
+ /* Convert Elf32_Sym struct to Elf64_Sym struct. We point at
+ * an Elf64_Sym local variable (sym_buf) to allow us to use the
+ * same pointer (sym) for both 32-bit and 64-bit instances.
+ */
+ sym = &sym_buf;
+ sym->st_name = sym32->st_name;
+ sym->st_info = sym32->st_info;
+ sym->st_other = sym32->st_other;
+ sym->st_shndx = sym32->st_shndx;
+ sym->st_value = sym32->st_value;
+ sym->st_size = sym32->st_size;
+ }
+
+ /* Determine relocation size */
+ if (is_32bit_abs_reloc(type, machine)) {
+ reloc_size = 4;
+ } else if (is_64bit_abs_reloc(type, machine)) {
+ reloc_size = 8;
+ } else {
+ return;
+ }
+
+
+ {
+ /* Assuming we do not need to do a READ_UNALIGNED here
+ at target_section + offset and add its value to
+ outval. Some ABIs say no read (for example MIPS),
+ but if some do then which ones? */
+ Dwarf_Unsigned outval = sym->st_value + addend;
+ WRITE_UNALIGNED(dbg,target_section + offset,
+ &outval,sizeof(outval),reloc_size);
+ }
+}
+
+
+
+static int
+apply_rela_entries(Dwarf_Debug dbg,
+ Dwarf_Bool is_64bit,
+ Dwarf_Endianness endianess,
+ Dwarf_Half machine,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ struct Dwarf_Elf_Rela *relas, unsigned int nrelas,
+ int *error)
+{
+ if ((target_section != NULL) && (relas != NULL)) {
+ unsigned int i;
+ for (i = 0; i < nrelas; i++) {
+ update_entry(dbg, is_64bit,
+ endianess,
+ machine,
+ &(relas)[i],
+ target_section,
+ symtab_section);
+ }
+ }
+ return DW_DLV_OK;
+}
+
+
+static int
+loop_through_relocations(
+ Dwarf_Debug dbg,
+ dwarf_elf_object_access_internals_t* obj,
+ struct Dwarf_Section_s *relocatablesec,
+ int *error)
+{
+ Dwarf_Small *target_section = 0;
+ Dwarf_Small *symtab_section = obj->symtab->dss_data;
+ Dwarf_Small *relocation_section = relocatablesec->dss_reloc_data;
+ Dwarf_Unsigned relocation_section_size =
+ relocatablesec->dss_reloc_size;
+ int ret = DW_DLV_ERROR;
+ struct Dwarf_Elf_Rela *relas = 0;
+ unsigned int nrelas = 0;
+ Dwarf_Small *mspace = 0;
+
+ ret = get_relocation_entries(obj->is_64bit,
+ obj->endianness,
+ obj->machine,
+ relocation_section,
+ relocation_section_size,
+ &relas, &nrelas, error);
+ if(ret != DW_DLV_OK) {
+ free(relas);
+ return ret;
+ }
+
+ /* Some systems read Elf in read-only memory via mmap or the like.
+ So the only safe thing is to copy the current data into
+ malloc space and refer to the malloc space instead of the
+ space returned by the elf library */
+ mspace = malloc(relocatablesec->dss_size);
+ if(!mspace) {
+ *error = DW_DLE_RELOC_SECTION_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ memcpy(mspace,relocatablesec->dss_data,relocatablesec->dss_size);
+ relocatablesec->dss_data = mspace;
+ target_section = relocatablesec->dss_data;
+ relocatablesec->dss_data_was_malloc = 1;
+
+ ret = apply_rela_entries(
+ dbg,
+ obj->is_64bit,
+ obj->endianness, obj->machine,
+ target_section,
+ symtab_section,
+ relas, nrelas, error);
+
+ free(relas);
+
+ return ret;
+}
+
+/*
+ Find the section data in dbg and find all the relevant
+ sections. Then do relocations.
+*/
+static int
+dwarf_elf_object_relocate_a_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Debug dbg,
+ int* error)
+{
+ int res = DW_DLV_ERROR;
+ dwarf_elf_object_access_internals_t*obj = 0;
+ struct Dwarf_Section_s * relocatablesec = 0;
+ if (section_index == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ obj = (dwarf_elf_object_access_internals_t*)obj_in;
+
+ /* The section to relocate must already be loaded into memory. */
+ res = find_section_to_relocate(dbg, section_index,&relocatablesec,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ /* Sun and possibly others do not always set sh_link in .debug_* sections.
+ So we cannot do full consistency checks. */
+ if(relocatablesec->dss_reloc_index == 0 ) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_SECTION_MISSING_INDEX;
+ return DW_DLV_ERROR;
+ }
+ /* Now load the relocations themselves. */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ relocatablesec->dss_reloc_index,
+ &relocatablesec->dss_reloc_data, error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ /* Now get the symtab. */
+ if (!obj->symtab) {
+ obj->symtab = &dbg->de_elf_symtab;
+ obj->strtab = &dbg->de_elf_strtab;
+ }
+ if( obj->symtab->dss_index != relocatablesec->dss_reloc_link) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_MISMATCH_RELOC_INDEX;
+ return DW_DLV_ERROR;
+ }
+ if( obj->strtab->dss_index != obj->symtab->dss_link) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_MISMATCH_STRTAB_INDEX;
+ return DW_DLV_ERROR;
+ }
+ if(!obj->symtab->dss_data) {
+ /* Now load the symtab */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ obj->symtab->dss_index,
+ &obj->symtab->dss_data, error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ if(! obj->strtab->dss_data) {
+ /* Now load the strtab */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ obj->strtab->dss_index,
+ &obj->strtab->dss_data,error);
+ if(res != DW_DLV_OK){
+ return res;
+ }
+ }
+
+ /* We have all the data we need in memory. */
+ res = loop_through_relocations(dbg,obj,relocatablesec,error);
+
+ return res;
+}
+
+/*
+ dwarf_elf_object_access_load_section
+ */
+static int
+dwarf_elf_object_access_load_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Small** section_data,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ if (section_index == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ {
+ Elf_Scn *scn = 0;
+ Elf_Data *data = 0;
+
+ scn = elf_getscn(obj->elf, section_index);
+ if (scn == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+
+ /*
+ When using libelf as a producer, section data may be stored
+ in multiple buffers. In libdwarf however, we only use libelf
+ as a consumer (there is a dwarf producer API, but it doesn't
+ use libelf). Because of this, this single call to elf_getdata
+ will retrieve the entire section in a single contiguous
+ buffer. */
+ data = elf_getdata(scn, NULL);
+ if (data == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+ *section_data = data->d_buf;
+ }
+ return DW_DLV_OK;
+}
+
+
+/* dwarf_elf_access method table. */
+static const struct Dwarf_Obj_Access_Methods_s dwarf_elf_object_access_methods =
+{
+ dwarf_elf_object_access_get_section_info,
+ dwarf_elf_object_access_get_byte_order,
+ dwarf_elf_object_access_get_length_size,
+ dwarf_elf_object_access_get_pointer_size,
+ dwarf_elf_object_access_get_section_count,
+ dwarf_elf_object_access_load_section,
+ dwarf_elf_object_relocate_a_section
+};
+
+
+/*
+ Interface for the ELF object file implementation.
+ */
+int
+dwarf_elf_object_access_init(dwarf_elf_handle elf,
+ int libdwarf_owns_elf,
+ Dwarf_Obj_Access_Interface** ret_obj,
+ int *err)
+{
+ int res = 0;
+ dwarf_elf_object_access_internals_t *internals = 0;
+ Dwarf_Obj_Access_Interface *intfc = 0;
+
+ internals = malloc(sizeof(dwarf_elf_object_access_internals_t));
+ if(!internals) {
+ /* Impossible case, we hope. Give up. */
+ return DW_DLV_ERROR;
+ }
+ memset(internals,0,sizeof(*internals));
+ res = dwarf_elf_object_access_internals_init(internals, elf, err);
+ if(res != DW_DLV_OK){
+ free(internals);
+ return DW_DLV_ERROR;
+ }
+ internals->libdwarf_owns_elf = libdwarf_owns_elf;
+
+ intfc = malloc(sizeof(Dwarf_Obj_Access_Interface));
+ if(!intfc) {
+ /* Impossible case, we hope. Give up. */
+ free(internals);
+ return DW_DLV_ERROR;
+ }
+ /* Initialize the interface struct */
+ intfc->object = internals;
+ intfc->methods = &dwarf_elf_object_access_methods;
+
+ *ret_obj = intfc;
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Clean up the Dwarf_Obj_Access_Interface returned by elf_access_init.
+ */
+void
+dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj)
+{
+ if(!obj) {
+ return;
+ }
+ if(obj->object) {
+ dwarf_elf_object_access_internals_t *internals =
+ (dwarf_elf_object_access_internals_t *)obj->object;
+ if(internals->libdwarf_owns_elf){
+ elf_end(internals->elf);
+ }
+ }
+ free(obj->object);
+ free(obj);
+}
+
+/*
+ This function returns the Elf * pointer
+ associated with a Dwarf_Debug.
+
+ This function only makes sense if ELF is implied.
+ */
+int
+dwarf_get_elf(Dwarf_Debug dbg, dwarf_elf_handle * elf,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Obj_Access_Interface_s * obj = 0;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ obj = dbg->de_obj_file;
+ if(obj) {
+ dwarf_elf_object_access_internals_t *internals =
+ (dwarf_elf_object_access_internals_t*)obj->object;
+ if(internals->elf == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FNO);
+ return (DW_DLV_ERROR);
+ }
+ *elf = internals->elf;
+ return DW_DLV_OK;
+
+ }
+ _dwarf_error(dbg, error, DW_DLE_FNO);
+ return DW_DLV_ERROR;
+}
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_elf_access.h b/usr/src/lib/libdwarf/common/dwarf_elf_access.h
new file mode 100644
index 0000000000..fd52c17938
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_elf_access.h
@@ -0,0 +1,55 @@
+#ifndef _DWARF_ELF_PORT_H
+#define _DWARF_ELF_PORT_H
+/*
+
+ Copyright (C) 2008-2010 David Anderson. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* ELF (usually libelf) object access for the generic object file interface */
+
+int
+dwarf_elf_object_access_init(dwarf_elf_handle elf ,
+ int libdwarf_owns_elf,
+ Dwarf_Obj_Access_Interface** ret_obj,
+ int *err );
+
+void
+dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj );
+
+/* End ELF object access for the generic object file interface */
+
+
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf_error.c b/usr/src/lib/libdwarf/common/dwarf_error.c
new file mode 100644
index 0000000000..7327529820
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_error.c
@@ -0,0 +1,410 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+/* Array to hold string representation of errors. Any time a
+ define is added to the list in libdwarf.h, a string should be
+ added to this Array
+*/
+
+const char *_dwarf_errmsgs[] = {
+
+ "No error (0)\n",
+ "DW_DLE_VMM 1 dwarf format/library version mismatch",
+ "DW_DLE_MAP 2 memory map failure",
+ "DW_DLE_LEE 3 libelf error",
+ "DW_DLE_NDS 4 no debug section",
+ "DW_DLE_NLS 5 no line section ",
+ "DW_DLE_ID 6 invalid descriptor for query ",
+ "DW_DLE_IOF 7 I/O failure ",
+ "DW_DLE_MAF 8 memory allocation failure ",
+ "DW_DLE_IA 9 invalid argument ",
+ "DW_DLE_MDE 10 mangled debugging entry ",
+ "DW_DLE_MLE 11 mangled line number entry ",
+ "DW_DLE_FNO 12 file not open ",
+ "DW_DLE_FNR 13 file not a regular file ",
+ "DW_DLE_FWA 14 file open with wrong access ",
+ "DW_DLE_NOB 15 not an object file ",
+ "DW_DLE_MOF 16 mangled object file header ",
+ "DW_DLE_EOLL 17 end of location list entries ",
+ "DW_DLE_NOLL 18 no location list section ",
+ "DW_DLE_BADOFF 19 Invalid offset ",
+ "DW_DLE_EOS 20 end of section ",
+ "DW_DLE_ATRUNC 21 abbreviations section appears truncated",
+ "DW_DLE_BADBITC 22 Address size passed to dwarf bad",
+
+ "DW_DLE_DBG_ALLOC 23 Unable to malloc a Dwarf_Debug structure",
+ "DW_DLE_FSTAT_ERROR 24 The file fd passed to dwarf_init "
+ "cannot be fstat()ed",
+ "DW_DLE_FSTAT_MODE_ERROR 25 The file mode bits do not "
+ "indicate that the file being opened via "
+ "dwarf_init() is a normal file",
+ "DW_DLE_INIT_ACCESS_WRONG 26 A call to dwarf_init had an "
+ "access of other than DW_DLC_READ",
+ "DW_DLE_ELF_BEGIN_ERROR 27 a call to "
+ "elf_begin(... ELF_C_READ_MMAP... ) failed",
+ "DW_DLE_ELF_GETEHDR_ERROR 28 a call to "
+ "elf32_getehdr() or elf64_getehdr() failed",
+ "DW_DLE_ELF_GETSHDR_ERROR 29 a call to "
+ "elf32_getshdr() or elf64_getshdr() failed",
+ "DW_DLE_ELF_STRPTR_ERROR 30 a call to "
+ "elf_strptr() failed trying to get a section name",
+ "DW_DLE_DEBUG_INFO_DUPLICATE 31 Only one .debug_info "
+ "section is allowed",
+ "DW_DLE_DEBUG_INFO_NULL 32 .debug_info section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_ABBREV_DUPLICATE 33 Only one .debug_abbrev "
+ "section is allowed",
+ "DW_DLE_DEBUG_ABBREV_NULL 34 .debug_abbrev section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_ARANGES_DUPLICATE 35 Only one .debug_aranges "
+ "section is allowed",
+ "DW_DLE_DEBUG_ARANGES_NULL 36 .debug_aranges section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_LINE_DUPLICATE 37 Only one .debug_line "
+ "section is allowed",
+ "DW_DLE_DEBUG_LINE_NULL (38) .debug_line section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_LOC_DUPLICATE (39) Only one .debug_loc "
+ "section is allowed",
+ "DW_DLE_DEBUG_LOC_NULL (40) .debug_loc section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_MACINFO_DUPLICATE (41) Only one .debug_macinfo "
+ "section is allowed",
+ "DW_DLE_DEBUG_MACINFO_NULL (42) .debug_macinfo section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_PUBNAMES_DUPLICATE (43) Only one .debug_pubnames "
+ "section is allowed",
+ "DW_DLE_DEBUG_PUBNAMES_NULL (44) .debug_pubnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_STR_DUPLICATE (45) Only one .debug_str "
+ "section is allowed",
+ "DW_DLE_DEBUG_STR_NULL (46) .debug_str section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_CU_LENGTH_ERROR (47)",
+ "DW_DLE_VERSION_STAMP_ERROR (48)",
+ "DW_DLE_ABBREV_OFFSET_ERROR (49)",
+ "DW_DLE_ADDRESS_SIZE_ERROR (50)",
+ "DW_DLE_DEBUG_INFO_PTR_NULL (51)",
+ "DW_DLE_DIE_NULL (52)",
+ "DW_DLE_STRING_OFFSET_BAD (53)",
+ "DW_DLE_DEBUG_LINE_LENGTH_BAD (54)",
+ "DW_DLE_LINE_PROLOG_LENGTH_BAD (55)",
+ "DW_DLE_LINE_NUM_OPERANDS_BAD",
+ "DW_DLE_LINE_SET_ADDR_ERROR",
+ "DW_DLE_LINE_EXT_OPCODE_BAD",
+ "DW_DLE_DWARF_LINE_NULL",
+ "DW_DLE_INCL_DIR_NUM_BAD",
+ "DW_DLE_LINE_FILE_NUM_BAD",
+ "DW_DLE_ALLOC_FAIL",
+ "DW_DLE_NO_CALLBACK_FUNC",
+ "DW_DLE_SECT_ALLOC",
+ "DW_DLE_FILE_ENTRY_ALLOC",
+ "DW_DLE_LINE_ALLOC",
+ "DW_DLE_FPGM_ALLOC",
+ "DW_DLE_INCDIR_ALLOC",
+ "DW_DLE_STRING_ALLOC",
+ "DW_DLE_CHUNK_ALLOC",
+ "DW_DLE_BYTEOFF_ERR",
+ "DW_DLE_CIE_ALLOC",
+ "DW_DLE_FDE_ALLOC",
+ "DW_DLE_REGNO_OVFL",
+ "DW_DLE_CIE_OFFS_ALLOC",
+ "DW_DLE_WRONG_ADDRESS",
+ "DW_DLE_EXTRA_NEIGHBORS",
+ "DW_DLE_WRONG_TAG",
+ "DW_DLE_DIE_ALLOC",
+ "DW_DLE_PARENT_EXISTS",
+ "DW_DLE_DBG_NULL",
+ "DW_DLE_DEBUGLINE_ERROR",
+ "DW_DLE_DEBUGFRAME_ERROR",
+ "DW_DLE_DEBUGINFO_ERROR",
+ "DW_DLE_ATTR_ALLOC",
+ "DW_DLE_ABBREV_ALLOC",
+ "DW_DLE_OFFSET_UFLW",
+ "DW_DLE_ELF_SECT_ERR",
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD",
+ "DW_DLE_FRAME_VERSION_BAD",
+ "DW_DLE_CIE_RET_ADDR_REG_ERROR",
+ "DW_DLE_FDE_NULL",
+ "DW_DLE_FDE_DBG_NULL",
+ "DW_DLE_CIE_NULL",
+ "DW_DLE_CIE_DBG_NULL",
+ "DW_DLE_FRAME_TABLE_COL_BAD",
+ "DW_DLE_PC_NOT_IN_FDE_RANGE",
+ "DW_DLE_CIE_INSTR_EXEC_ERROR",
+ "DW_DLE_FRAME_INSTR_EXEC_ERROR",
+ "DW_DLE_FDE_PTR_NULL",
+ "DW_DLE_RET_OP_LIST_NULL",
+ "DW_DLE_LINE_CONTEXT_NULL",
+ "DW_DLE_DBG_NO_CU_CONTEXT",
+ "DW_DLE_DIE_NO_CU_CONTEXT",
+ "DW_DLE_FIRST_DIE_NOT_CU",
+ "DW_DLE_NEXT_DIE_PTR_NULL",
+ "DW_DLE_DEBUG_FRAME_DUPLICATE Only one .debug_frame "
+ "section is allowed",
+ "DW_DLE_DEBUG_FRAME_NULL .debug_frame section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_ABBREV_DECODE_ERROR",
+ "DW_DLE_DWARF_ABBREV_NULL",
+ "DW_DLE_ATTR_NULL",
+ "DW_DLE_DIE_BAD",
+ "DW_DLE_DIE_ABBREV_BAD",
+ "DW_DLE_ATTR_FORM_BAD",
+ "DW_DLE_ATTR_NO_CU_CONTEXT",
+ "DW_DLE_ATTR_FORM_SIZE_BAD",
+ "DW_DLE_ATTR_DBG_NULL",
+ "DW_DLE_BAD_REF_FORM",
+ "DW_DLE_ATTR_FORM_OFFSET_BAD",
+ "DW_DLE_LINE_OFFSET_BAD",
+ "DW_DLE_DEBUG_STR_OFFSET_BAD",
+ "DW_DLE_STRING_PTR_NULL",
+ "DW_DLE_PUBNAMES_VERSION_ERROR",
+ "DW_DLE_PUBNAMES_LENGTH_BAD",
+ "DW_DLE_GLOBAL_NULL",
+ "DW_DLE_GLOBAL_CONTEXT_NULL",
+ "DW_DLE_DIR_INDEX_BAD",
+ "DW_DLE_LOC_EXPR_BAD",
+ "DW_DLE_DIE_LOC_EXPR_BAD",
+ "DW_DLE_ADDR_ALLOC",
+ "DW_DLE_OFFSET_BAD",
+ "DW_DLE_MAKE_CU_CONTEXT_FAIL",
+ "DW_DLE_REL_ALLOC",
+ "DW_DLE_ARANGE_OFFSET_BAD",
+ "DW_DLE_SEGMENT_SIZE_BAD",
+ "DW_DLE_ARANGE_LENGTH_BAD",
+ "DW_DLE_ARANGE_DECODE_ERROR",
+ "DW_DLE_ARANGES_NULL",
+ "DW_DLE_ARANGE_NULL",
+ "DW_DLE_NO_FILE_NAME",
+ "DW_DLE_NO_COMP_DIR",
+ "DW_DLE_CU_ADDRESS_SIZE_BAD",
+ "DW_DLE_INPUT_ATTR_BAD",
+ "DW_DLE_EXPR_NULL",
+ "DW_DLE_BAD_EXPR_OPCODE",
+ "DW_DLE_EXPR_LENGTH_BAD",
+ "DW_DLE_MULTIPLE_RELOC_IN_EXPR",
+ "DW_DLE_ELF_GETIDENT_ERROR",
+ "DW_DLE_NO_AT_MIPS_FDE",
+ "DW_DLE_NO_CIE_FOR_FDE",
+ "DW_DLE_DIE_ABBREV_LIST_NULL",
+ "DW_DLE_DEBUG_FUNCNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_FUNCNAMES_NULL .debug_funcnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD",
+ "DW_DLE_FUNC_NULL",
+ "DW_DLE_FUNC_CONTEXT_NULL",
+ "DW_DLE_DEBUG_TYPENAMES_DUPLICATE",
+ "DW_DLE_DEBUG_TYPENAMES_NULL .debug_typenames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD",
+ "DW_DLE_TYPE_NULL",
+ "DW_DLE_TYPE_CONTEXT_NULL",
+ "DW_DLE_DEBUG_VARNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_VARNAMES_NULL .debug_varnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_VARNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_VARNAMES_LENGTH_BAD",
+ "DW_DLE_VAR_NULL",
+ "DW_DLE_VAR_CONTEXT_NULL",
+ "DW_DLE_DEBUG_WEAKNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_WEAKNAMES_NULL .debug_weaknames section present but "
+ "elf_getdata() failed or section is zero-length",
+
+ "DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD",
+ "DW_DLE_WEAK_NULL",
+ "DW_DLE_WEAK_CONTEXT_NULL (175)",
+ "DW_DLE_LOCDESC_COUNT_WRONG (176)",
+ "DW_DLE_MACINFO_STRING_NULL (177)",
+ "DW_DLE_MACINFO_STRING_EMPTY (178)",
+ "DW_DLE_MACINFO_INTERNAL_ERROR_SPACE (179)",
+ "DW_DLE_MACINFO_MALLOC_FAIL (180)",
+ "DW_DLE_DEBUGMACINFO_ERROR (181)",
+ "DW_DLE_DEBUG_MACRO_LENGTH_BAD (182)",
+ "DW_DLE_DEBUG_MACRO_MAX_BAD (183)",
+ "DW_DLE_DEBUG_MACRO_INTERNAL_ERR (184)",
+ "DW_DLE_DEBUG_MACRO_MALLOC_SPACE (185)",
+ "DW_DLE_DEBUG_MACRO_INCONSISTENT (186)",
+ "DW_DLE_DF_NO_CIE_AUGMENTATION(187)",
+ "DW_DLE_DF_REG_NUM_TOO_HIGH(188)",
+ "DW_DLE_DF_MAKE_INSTR_NO_INIT(189)",
+ "DW_DLE_DF_NEW_LOC_LESS_OLD_LOC(190)",
+ "DW_DLE_DF_POP_EMPTY_STACK(191)",
+ "DW_DLE_DF_ALLOC_FAIL(192)",
+ "DW_DLE_DF_FRAME_DECODING_ERROR(193)",
+ "DW_DLE_DEBUG_LOC_SECTION_SHORT(194)",
+ "DW_DLE_FRAME_AUGMENTATION_UNKNOWN(195)",
+ "DW_DLE_PUBTYPE_CONTEXT(196)",
+ "DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD(197)",
+ "DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR(198)",
+ "DW_DLE_DEBUG_PUBTYPES_DUPLICATE(199)",
+ "DW_DLE_FRAME_CIE_DECODE_ERROR(200)",
+ "DW_DLE_FRAME_REGISTER_UNREPRESENTABLE(201)",
+ "DW_DLE_FRAME_REGISTER_COUNT_MISMATCH(202)",
+ "DW_DLE_LINK_LOOP(203)",
+ "DW_DLE_STRP_OFFSET_BAD(204)",
+ "DW_DLE_DEBUG_RANGES_DUPLICATE(205)",
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD(206)",
+ "DW_DLE_DEBUG_RANGES_MISSING_END(207)",
+ "DW_DLE_DEBUG_RANGES_OUT_OF_MEM(208)",
+ "DW_DLE_DEBUG_SYMTAB_ERR(209)",
+ "DW_DLE_DEBUG_STRTAB_ERR(210)",
+ "DW_DLE_RELOC_MISMATCH_INDEX(211)",
+ "DW_DLE_RELOC_MISMATCH_RELOC_INDEX(212)",
+ "DW_DLE_RELOC_MISMATCH_STRTAB_INDEX(213)",
+ "DW_DLE_RELOC_SECTION_MISMATCH(214)",
+ "DW_DLE_RELOC_SECTION_MISSING_INDEX(215)",
+ "DW_DLE_RELOC_SECTION_LENGTH_ODD(216)",
+ "DW_DLE_RELOC_SECTION_PTR_NULL(217)",
+ "DW_DLE_RELOC_SECTION_MALLOC_FAIL(218)",
+ "DW_DLE_NO_ELF64_SUPPORT(219)",
+ "DW_DLE_MISSING_ELF64_SUPPORT(220)",
+ "DW_DLE_ORPHAN_FDE(221)",
+ "DW_DLE_DUPLICATE_INST_BLOCK(222)",
+ "DW_DLE_BAD_REF_SIG8_FORM(223)",
+ "DW_DLE_ATTR_EXPRLOC_FORM_BAD(224)",
+ "DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD(225)",
+ "DW_DLE_NOT_REF_FORM(226)",
+ "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE(227)"
+};
+
+
+
+
+/*
+ This function performs error handling as described in the
+ libdwarf consumer document section 3. Dbg is the Dwarf_debug
+ structure being processed. Error is a pointer to the pointer
+ to the error descriptor that will be returned. Errval is an
+ error code listed in dwarf_error.h.
+*/
+void
+_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, Dwarf_Sword errval)
+{
+ Dwarf_Error errptr;
+
+ /*
+ Allow NULL dbg on entry, since sometimes that can happen and we
+ want to report the upper-level error, not this one. */
+ if (error != NULL) {
+
+ /*
+ If dbg is NULL, use the alternate error struct. However,
+ this will overwrite the earlier error. */
+ if (dbg != NULL) {
+ errptr =
+ (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure, "
+ "abort() in libdwarf.\n");
+ abort();
+ }
+ } else {
+ /* We have no dbg to work with. dwarf_init failed. We hack
+ up a special area. */
+ errptr = _dwarf_special_no_dbg_error_malloc();
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure, "
+ "abort() in libdwarf..\n");
+ abort();
+ }
+ }
+
+ errptr->er_errval = errval;
+ *error = errptr;
+ return;
+ }
+
+ if (dbg != NULL && dbg->de_errhand != NULL) {
+ errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
+ if (errptr == NULL) {
+ fprintf(stderr, "Could not allocate Dwarf_Error structure,"
+ " abort() in libdwarf.\n");
+ abort();
+ }
+ errptr->er_errval = errval;
+ dbg->de_errhand(errptr, dbg->de_errarg);
+ return;
+ }
+ fprintf(stderr,
+ "abort() in libdwarf. No error argument, no handler.\n");
+ abort();
+}
+
+
+Dwarf_Unsigned
+dwarf_errno(Dwarf_Error error)
+{
+ if (error == NULL) {
+ return (0);
+ }
+
+ return (error->er_errval);
+}
+
+
+/*
+*/
+char *
+dwarf_errmsg(Dwarf_Error error)
+{
+ if (error == NULL) {
+ return "Dwarf_Error is NULL";
+ }
+
+ if (error->er_errval > (sizeof(_dwarf_errmsgs) / sizeof(char *))) {
+ return "Dwarf_Error value out of range";
+ }
+
+ return ((char *) _dwarf_errmsgs[error->er_errval]);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_error.h b/usr/src/lib/libdwarf/common/dwarf_error.h
new file mode 100644
index 0000000000..27acf70db0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_error.h
@@ -0,0 +1,43 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+void _dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error,
+ Dwarf_Sword errval);
+
+struct Dwarf_Error_s {
+ Dwarf_Sword er_errval;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_form.c b/usr/src/lib/libdwarf/common/dwarf_form.c
new file mode 100644
index 0000000000..fcdd64230c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_form.c
@@ -0,0 +1,963 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_die_deliv.h"
+
+int
+dwarf_hasform(Dwarf_Attribute attr,
+ Dwarf_Half form,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (attr->ar_attribute_form == form);
+ return DW_DLV_OK;
+}
+
+/* Not often called, we do not worry about efficiency here.
+ The dwarf_whatform() call does the sanity checks for us.
+*/
+int
+dwarf_whatform_direct(Dwarf_Attribute attr,
+ Dwarf_Half * return_form, Dwarf_Error * error)
+{
+ int res = dwarf_whatform(attr, return_form, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *return_form = attr->ar_attribute_form_direct;
+ return (DW_DLV_OK);
+}
+void *
+dwarf_uncompress_integer_block(
+ Dwarf_Debug dbg,
+ Dwarf_Bool unit_is_signed,
+ Dwarf_Small unit_length_in_bits,
+ void* input_block,
+ Dwarf_Unsigned input_length_in_bytes,
+ Dwarf_Unsigned* output_length_in_units_ptr,
+ Dwarf_Error* error
+)
+{
+ Dwarf_Unsigned output_length_in_units = 0;
+ void * output_block = 0;
+ int i = 0;
+ char * ptr = 0;
+ int remain = 0;
+ Dwarf_sfixed * array = 0;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ if (unit_is_signed == false ||
+ unit_length_in_bits != 32 ||
+ input_block == NULL ||
+ input_length_in_bytes == 0 ||
+ output_length_in_units_ptr == NULL) {
+
+ _dwarf_error(NULL, error, DW_DLE_BADBITC);
+ return ((void *) DW_DLV_BADADDR);
+ }
+
+ /* At this point we assume the format is: signed 32 bit */
+
+ /* first uncompress everything to find the total size. */
+
+ output_length_in_units = 0;
+ remain = input_length_in_bytes;
+ ptr = input_block;
+ while (remain > 0) {
+ Dwarf_Signed num;
+ Dwarf_Word len;
+ num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len);
+ ptr += len;
+ remain -= len;
+ output_length_in_units++;
+ }
+
+ if (remain != 0) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ /* then alloc */
+
+ output_block = (void *)
+ _dwarf_get_alloc(dbg,
+ DW_DLA_STRING,
+ output_length_in_units * (unit_length_in_bits / 8));
+ if (output_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((void*)DW_DLV_BADADDR);
+ }
+
+ /* then uncompress again and copy into new buffer */
+
+ array = (Dwarf_sfixed *) output_block;
+ remain = input_length_in_bytes;
+ ptr = input_block;
+ for (i=0; i<output_length_in_units && remain>0; i++) {
+ Dwarf_Signed num;
+ Dwarf_Word len;
+ num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len);
+ ptr += len;
+ remain -= len;
+ array[i] = num;
+ }
+
+ if (remain != 0) {
+ dwarf_dealloc(dbg, (unsigned char *)output_block, DW_DLA_STRING);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ *output_length_in_units_ptr = output_length_in_units;
+ return output_block;
+}
+
+void
+dwarf_dealloc_uncompressed_block(Dwarf_Debug dbg, void * space)
+{
+ dwarf_dealloc(dbg, space, DW_DLA_STRING);
+}
+
+
+int
+dwarf_whatform(Dwarf_Attribute attr,
+ Dwarf_Half * return_form, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_form = attr->ar_attribute_form;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function is analogous to dwarf_whatform.
+ It returns the attribute in attr instead of
+ the form.
+*/
+int
+dwarf_whatattr(Dwarf_Attribute attr,
+ Dwarf_Half * return_attr, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_attr = (attr->ar_attribute);
+ return DW_DLV_OK;
+}
+
+
+/*
+ A global offset cannot be returned by this interface:
+ see dwarf_global_formref().
+
+ DW_FORM_ref_addr is considered an incorrect form
+ for this call because DW_FORM_ref_addr is a global-offset into
+ the debug_info section.
+
+ For the same reason DW_FORM_data4/data8 are not returned
+ from this function.
+
+ For the same reason DW_FORM_sec_offset is not returned
+ from this function, DW_FORM_sec_offset is a global offset
+ (to various sections, not a CU relative offset.
+
+ DW_FORM_ref_addr has a value which was documented in
+ DWARF2 as address-size but which was always an offset
+ so should have always been offset size (wording
+ corrected in DWARF3).
+
+
+*/
+int
+dwarf_formref(Dwarf_Attribute attr,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ break;
+
+ case DW_FORM_ref2:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ break;
+
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ break;
+
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ break;
+
+ case DW_FORM_ref_udata:
+ offset = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL);
+ break;
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Check that offset is within current cu portion of .debug_info. */
+ if (offset >= cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_offset = (offset);
+ return DW_DLV_OK;
+}
+
+/* dwarf_formsig8 returns in the caller-provided 8 byte area
+ the 8 bytes of a DW_FORM_ref_sig8 (copying the bytes
+ directly to the caller). Not a string, an 8 byte
+ MD5 hash. This function is new in DWARF4 libdwarf.
+*/
+int dwarf_formsig8(Dwarf_Attribute attr,
+ Dwarf_Sig8 * returned_sig_bytes,
+ Dwarf_Error* error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned field_end_offset = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if(attr->ar_attribute_form != DW_FORM_ref_sig8 ) {
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_SIG8_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ field_end_offset = attr->ar_debug_info_ptr + sizeof(Dwarf_Sig8) -
+ (dbg->de_debug_info.dss_data + cu_context->cc_debug_info_offset);
+ /* Check that offset is within current cu portion of .debug_info. */
+ if (field_end_offset > cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ memcpy(returned_sig_bytes, attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Sig8));
+ return DW_DLV_OK;
+}
+
+
+/*
+ Since this returns section-relative debug_info offsets,
+ this can represent all REFERENCE forms correctly
+ and allows all applicable forms.
+
+ DW_FORM_ref_addr has a value which was documented in
+ DWARF2 as address-size but which was always an offset
+ so should have always been offset size (wording
+ corrected in DWARF3).
+
+ See the DWARF4 document for the 3 cases fitting
+ reference forms. The caller must determine which section the
+ reference 'points' to. The function added in November 2009,
+ dwarf_get_form_class(), helps in this regard.
+
+*/
+int
+dwarf_global_formref(Dwarf_Attribute attr,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Addr ref_addr = 0;
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Half context_version = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+ context_version = cu_context->cc_version_stamp;
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ goto fixoffset;
+
+ case DW_FORM_ref2:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ goto fixoffset;
+
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ goto fixoffset;
+
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ goto fixoffset;
+
+ case DW_FORM_ref_udata:
+ offset = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL);
+
+ fixoffset: /* we have a local offset, make it
+ global */
+
+ /* check legality of offset */
+ if (offset >= cu_context->cc_length +
+ cu_context->cc_length_size +
+ cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* globalize the offset */
+ offset += cu_context->cc_debug_info_offset;
+ break;
+ /* The DWARF2 document did not make clear that
+ DW_FORM_data4( and 8) were references with
+ global offsets to some section.
+ That was first clearly documented in DWARF3.
+ In DWARF4 these two forms are no longer references. */
+ case DW_FORM_data4:
+ if(context_version == DW_CU_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ /* The offset is global. */
+ break;
+ case DW_FORM_data8:
+ if(context_version == DW_CU_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ /* The offset is global. */
+ break;
+ case DW_FORM_ref_addr:
+ case DW_FORM_sec_offset:
+ {
+ /* DW_FORM_sec_offset first exists in DWARF4.*/
+ /* It is up to the caller to know what the offset
+ of DW_FORM_sec_offset refers to,
+ the offset is not going to refer to .debug_info! */
+ unsigned length_size = cu_context->cc_length_size;
+ if(length_size == 4) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ } else if (length_size == 8) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ } else {
+ _dwarf_error(dbg, error, DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ break;
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ /* We do not know what section the offset refers to, so
+ we have no way to check it for correctness. */
+ *ret_offset = offset;
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_formaddr(Dwarf_Attribute attr,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if (attr->ar_attribute_form == DW_FORM_addr
+ /* || attr->ar_attribute_form == DW_FORM_ref_addr Allowance of
+ DW_FORM_ref_addr was a mistake. The value returned in that
+ case is NOT an address it is a global debug_info offset (ie,
+ not CU-relative offset within the CU in debug_info). The
+ Dwarf document refers to it as an address (misleadingly) in
+ sec 6.5.4 where it describes the reference form. It is
+ address-sized so that the linker can easily update it, but
+ it is a reference inside the debug_info section. No longer
+ allowed. */
+ ) {
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ attr->ar_debug_info_ptr,
+ cu_context->cc_address_size);
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+ }
+
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formflag(Dwarf_Attribute attr,
+ Dwarf_Bool * ret_bool, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (attr->ar_attribute_form == DW_FORM_flag_present) {
+ /* Implicit means we don't read any data at all. Just
+ the existence of the Form does it. DWARF4. */
+ *ret_bool = 1;
+ return (DW_DLV_OK);
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_flag) {
+ *ret_bool = (*(Dwarf_Small *) attr->ar_debug_info_ptr != 0);
+ return (DW_DLV_OK);
+ }
+ _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formudata(Dwarf_Attribute attr,
+ Dwarf_Unsigned * return_uval, Dwarf_Error * error)
+{
+ Dwarf_Unsigned ret_value = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_data1:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Small));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+
+ /* READ_UNALIGNED does the right thing as it reads
+ the right number bits and generates host order.
+ So we can just assign to *return_uval. */
+ case DW_FORM_data2:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data4:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_ufixed));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data8:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Unsigned));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+ break;
+ case DW_FORM_udata:
+ ret_value =
+ (_dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+
+
+ /* see bug 583450. We do not allow reading sdata from a udata
+ value. Caller can retry, calling sdata */
+
+
+ default:
+ break;
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formsdata(Dwarf_Attribute attr,
+ Dwarf_Signed * return_sval, Dwarf_Error * error)
+{
+ Dwarf_Signed ret_value = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_data1:
+ *return_sval = (*(Dwarf_Sbyte *) attr->ar_debug_info_ptr);
+ return DW_DLV_OK;
+
+ /* READ_UNALIGNED does not sign extend.
+ So we have to use a cast to get the
+ value sign extended in the right way for each case. */
+ case DW_FORM_data2:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Shalf));
+ *return_sval = (Dwarf_Shalf) ret_value;
+ return DW_DLV_OK;
+
+ }
+
+ case DW_FORM_data4:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_sfixed));
+ *return_sval = (Dwarf_sfixed) ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data8:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Signed));
+ *return_sval = (Dwarf_Signed) ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_sdata:
+ ret_value =
+ (_dwarf_decode_s_leb128(attr->ar_debug_info_ptr, NULL));
+ *return_sval = ret_value;
+ return DW_DLV_OK;
+
+
+ /* see bug 583450. We do not allow reading sdata from a udata
+ value. Caller can retry, calling sdata */
+
+
+ default:
+ break;
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formblock(Dwarf_Attribute attr,
+ Dwarf_Block ** return_block, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small *data = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Block *ret_block = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_block1:
+ length = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_Small);
+ break;
+
+ case DW_FORM_block2:
+ READ_UNALIGNED(dbg, length, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_Half);
+ break;
+
+ case DW_FORM_block4:
+ READ_UNALIGNED(dbg, length, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_ufixed);
+ break;
+
+ case DW_FORM_block:
+ length = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr,
+ &leb128_length);
+ data = attr->ar_debug_info_ptr + leb128_length;
+ break;
+
+ default:
+ _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Check that block lies within current cu in .debug_info. */
+ if (attr->ar_debug_info_ptr + length >=
+ dbg->de_debug_info.dss_data + cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size +
+ cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_block = (Dwarf_Block *) _dwarf_get_alloc(dbg, DW_DLA_BLOCK, 1);
+ if (ret_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_block->bl_len = length;
+ ret_block->bl_data = (Dwarf_Ptr) data;
+ ret_block->bl_from_loclist = 0;
+ ret_block->bl_section_offset = data - dbg->de_debug_info.dss_data;
+
+
+ *return_block = ret_block;
+ return (DW_DLV_OK);
+}
+
+
+/* Contrary to long standing documentation,
+ The string pointer returned thru return_str must
+ never have dwarf_dealloc() applied to it.
+ Documentation fixed July 2005.
+*/
+int
+dwarf_formstring(Dwarf_Attribute attr,
+ char **return_str, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ int res = DW_DLV_ERROR;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if (attr->ar_attribute_form == DW_FORM_string) {
+
+ void *begin = attr->ar_debug_info_ptr;
+
+ if (0 == dbg->de_assume_string_in_bounds) {
+ /* Check that string lies within current cu in .debug_info.
+ */
+ void *end = dbg->de_debug_info.dss_data +
+ cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size +
+ cu_context->cc_extension_size;
+ if (0 == _dwarf_string_valid(begin, end)) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *return_str = (char *) (begin);
+ return DW_DLV_OK;
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_strp) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ cu_context->cc_length_size);
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ if (0 == dbg->de_assume_string_in_bounds) {
+ /* Check that string lies within current cu in .debug_info.
+ */
+ void *end = dbg->de_debug_str.dss_data +
+ dbg->de_debug_str.dss_size;
+ void*begin = dbg->de_debug_str.dss_data + offset;
+ if (0 == _dwarf_string_valid(begin, end)) {
+ _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *return_str = (char *) (dbg->de_debug_str.dss_data + offset);
+ return DW_DLV_OK;
+ }
+
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+int
+dwarf_formexprloc(Dwarf_Attribute attr,
+ Dwarf_Unsigned * return_exprlen,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_exprloc ) {
+ Dwarf_Unsigned exprlen =
+ (_dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL));
+ Dwarf_Small * addr = attr->ar_debug_info_ptr;
+ *return_exprlen = exprlen;
+ *block_ptr = addr + exprlen;
+ return DW_DLV_OK;
+
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_EXPRLOC_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame.c b/usr/src/lib/libdwarf/common/dwarf_frame.c
new file mode 100644
index 0000000000..3a825ee925
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame.c
@@ -0,0 +1,2442 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* Using Arange as a way to build a
+ list */
+
+#define FDE_NULL_CHECKS_AND_SET_DBG(fde,dbg ) \
+ do { \
+ if ((fde) == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL); \
+ return (DW_DLV_ERROR); \
+ } \
+ (dbg)= (fde)->fd_dbg; \
+ if ((dbg) == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);\
+ return (DW_DLV_ERROR); \
+ } } while (0)
+
+
+#define MIN(a,b) (((a) < (b))? a:b)
+
+static void _dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg,
+ int last_reg_num,
+ int initial_value);
+static int dwarf_initialize_fde_table(Dwarf_Debug dbg,
+ struct Dwarf_Frame_s *fde_table,
+ unsigned table_real_data_size,
+ Dwarf_Error * error);
+static void dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table);
+
+#if 0
+/* Only used for debugging libdwarf. */
+static void dump_frame_rule(char *msg,
+ struct Dwarf_Reg_Rule_s *reg_rule);
+#endif
+
+
+
+/*
+ This function is the heart of the debug_frame stuff. Don't even
+ think of reading this without reading both the Libdwarf and
+ consumer API carefully first. This function basically executes
+ frame instructions contained in a Cie or an Fde, but does in a
+ number of different ways depending on the information sought.
+ Start_instr_ptr points to the first byte of the frame instruction
+ stream, and final_instr_ptr to the to the first byte after the
+ last.
+
+ The offsets returned in the frame instructions are factored. That
+ is they need to be multiplied by either the code_alignment_factor
+ or the data_alignment_factor, as appropriate to obtain the actual
+ offset. This makes it possible to expand an instruction stream
+ without the corresponding Cie. However, when an Fde frame instr
+ sequence is being expanded there must be a valid Cie with a pointer
+ to an initial table row.
+
+
+ If successful, returns DW_DLV_OK
+ And sets returned_count thru the pointer
+ if make_instr is true.
+ If make_instr is false returned_count
+ should NOT be used by the caller (returned_count
+ is set to 0 thru the pointer by this routine...)
+ If unsuccessful, returns DW_DLV_ERROR
+ and sets returned_error to the error code
+
+ It does not do a whole lot of input validation being a private
+ function. Please make sure inputs are valid.
+
+ (1) If make_instr is true, it makes a list of pointers to
+ Dwarf_Frame_Op structures containing the frame instructions
+ executed. A pointer to this list is returned in ret_frame_instr.
+ Make_instr is true only when a list of frame instructions is to be
+ returned. In this case since we are not interested in the contents
+ of the table, the input Cie can be NULL. This is the only case
+ where the inpute Cie can be NULL.
+
+ (2) If search_pc is true, frame instructions are executed till
+ either a location is reached that is greater than the search_pc_val
+ provided, or all instructions are executed. At this point the
+ last row of the table generated is returned in a structure.
+ A pointer to this structure is supplied in table.
+
+ (3) This function is also used to create the initial table row
+ defined by a Cie. In this case, the Dwarf_Cie pointer cie, is
+ NULL. For an FDE, however, cie points to the associated Cie.
+
+ make_instr - make list of frame instr? 0/1
+ ret_frame_instr - Ptr to list of ptrs to frame instrs
+ search_pc - Search for a pc value? 0/1
+ search_pc_val - Search for this pc value
+ initial_loc - Initial code location value.
+ start_instr_ptr - Ptr to start of frame instrs.
+ final_instr_ptr - Ptr just past frame instrs.
+ table - Ptr to struct with last row.
+ cie - Ptr to Cie used by the Fde.
+ Different cies may have distinct address-sizes, so the cie
+ is used, not de_pointer_size.
+
+*/
+
+int
+_dwarf_exec_frame_instr(Dwarf_Bool make_instr,
+ Dwarf_Frame_Op ** ret_frame_instr,
+ Dwarf_Bool search_pc,
+ Dwarf_Addr search_pc_val,
+ Dwarf_Addr initial_loc,
+ Dwarf_Small * start_instr_ptr,
+ Dwarf_Small * final_instr_ptr,
+ Dwarf_Frame table,
+ Dwarf_Cie cie,
+ Dwarf_Debug dbg,
+ Dwarf_Half reg_num_of_cfa,
+ Dwarf_Sword * returned_count,
+ int *returned_error)
+{
+#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \
+ do { \
+ if ((macreg) >= (machigh_reg) || (macreg) < 0) { \
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); \
+ } \
+ } /*CONSTCOND */ while(0)
+#define SIMPLE_ERROR_RETURN(code) \
+ free(localregtab); \
+ *returned_error = code; \
+ return DW_DLV_ERROR
+
+ /* Sweeps the frame instructions. */
+ Dwarf_Small *instr_ptr;
+
+ /* Register numbers not limited to just 255, thus not using
+ Dwarf_Small. */
+ typedef int reg_num_type;
+
+ Dwarf_Unsigned factored_N_value;
+ Dwarf_Signed signed_factored_N_value;
+ Dwarf_Addr current_loc = initial_loc; /* code location/
+ pc-value
+ corresponding to the
+ frame instructions.
+ Starts at zero when
+ the caller has no
+ value to pass in. */
+
+ /* Must be min de_pointer_size bytes and must be at least sizeof
+ Dwarf_ufixed */
+ Dwarf_Unsigned adv_loc = 0;
+
+ int reg_count = dbg->de_frame_reg_rules_entry_count;
+ struct Dwarf_Reg_Rule_s *localregtab = calloc(reg_count,
+ sizeof(struct
+ Dwarf_Reg_Rule_s));
+
+ struct Dwarf_Reg_Rule_s cfa_reg;
+
+
+ /* This is used to end executing frame instructions. */
+ /* Becomes true when search_pc is true and current_loc */
+ /* is greater than search_pc_val. */
+ Dwarf_Bool search_over = false;
+
+ /* Used by the DW_FRAME_advance_loc instr */
+ /* to hold the increment in pc value. */
+ Dwarf_Addr adv_pc;
+
+ /* Contains the length in bytes of */
+ /* an leb128 encoded number. */
+ Dwarf_Word leb128_length;
+
+ Dwarf_Half address_size = (cie)? cie->ci_address_size:
+ dbg->de_pointer_size;
+
+ /* Counts the number of frame instructions executed. */
+ Dwarf_Word instr_count = 0;
+
+ /*
+ These contain the current fields of the current frame
+ instruction. */
+ Dwarf_Small fp_base_op = 0;
+ Dwarf_Small fp_extended_op;
+ reg_num_type fp_register;
+
+ /* The value in fp_offset may be signed, though we call it
+ unsigned. This works ok for 2-s complement arithmetic. */
+ Dwarf_Unsigned fp_offset;
+ Dwarf_Off fp_instr_offset;
+
+ /*
+ Stack_table points to the row (Dwarf_Frame ie) being pushed or
+ popped by a remember or restore instruction. Top_stack points to
+ the top of the stack of rows. */
+ Dwarf_Frame stack_table = NULL;
+ Dwarf_Frame top_stack = NULL;
+
+ /*
+ These are used only when make_instr is true. Curr_instr is a
+ pointer to the current frame instruction executed.
+ Curr_instr_ptr, head_instr_list, and curr_instr_list are used to
+ form a chain of Dwarf_Frame_Op structs. Dealloc_instr_ptr is
+ used to deallocate the structs used to form the chain.
+ Head_instr_block points to a contiguous list of pointers to the
+ Dwarf_Frame_Op structs executed. */
+ Dwarf_Frame_Op *curr_instr;
+ Dwarf_Chain curr_instr_item, dealloc_instr_item;
+ Dwarf_Chain head_instr_chain = NULL;
+ Dwarf_Chain tail_instr_chain = NULL;
+ Dwarf_Frame_Op *head_instr_block;
+
+ /*
+ These are the alignment_factors taken from the Cie provided.
+ When no input Cie is provided they are set to 1, because only
+ factored offsets are required. */
+ Dwarf_Sword code_alignment_factor = 1;
+ Dwarf_Sword data_alignment_factor = 1;
+
+ /*
+ This flag indicates when an actual alignment factor is needed.
+ So if a frame instruction that computes an offset using an
+ alignment factor is encountered when this flag is set, an error
+ is returned because the Cie did not have a valid augmentation. */
+ Dwarf_Bool need_augmentation = false;
+
+ Dwarf_Word i;
+
+ /* Initialize first row from associated Cie. Using temp regs
+ explicity */
+
+ if (localregtab == 0) {
+ SIMPLE_ERROR_RETURN(DW_DLE_ALLOC_FAIL);
+ }
+ {
+ struct Dwarf_Reg_Rule_s *t1reg = localregtab;
+ struct Dwarf_Reg_Rule_s *t1end = t1reg + reg_count;
+
+ if (cie != NULL && cie->ci_initial_table != NULL) {
+ struct Dwarf_Reg_Rule_s *t2reg =
+ cie->ci_initial_table->fr_reg;
+
+ if (reg_count != cie->ci_initial_table->fr_reg_count) {
+ /* Should never happen, it makes no sense to have the
+ table sizes change. There is no real allowance for
+ the set of registers to change dynamically in a
+ single Dwarf_Debug (except the size can be set near
+ initial Dwarf_Debug creation time). */
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_FRAME_REGISTER_COUNT_MISMATCH);
+ }
+
+ for (; t1reg < t1end; t1reg++, t2reg++) {
+ *t1reg = *t2reg;
+ }
+ cfa_reg = cie->ci_initial_table->fr_cfa_rule;
+ } else {
+ _dwarf_init_regrule_table(t1reg,
+ reg_count,
+ dbg->de_frame_rule_initial_value);
+ _dwarf_init_regrule_table(&cfa_reg, 1,
+ dbg->de_frame_rule_initial_value);
+ }
+ }
+
+ /*
+ The idea here is that the code_alignment_factor and
+ data_alignment_factor which are needed for certain instructions
+ are valid only when the Cie has a proper augmentation string. So
+ if the augmentation is not right, only Frame instruction can be
+ read. */
+ if (cie != NULL && cie->ci_augmentation != NULL) {
+ code_alignment_factor = cie->ci_code_alignment_factor;
+ data_alignment_factor = cie->ci_data_alignment_factor;
+ } else {
+ need_augmentation = !make_instr;
+ }
+
+ instr_ptr = start_instr_ptr;
+ while ((instr_ptr < final_instr_ptr) && (!search_over)) {
+ Dwarf_Small instr = 0;
+ Dwarf_Small opcode = 0;
+ reg_num_type reg_no = 0;
+
+ fp_instr_offset = instr_ptr - start_instr_ptr;
+ instr = *(Dwarf_Small *) instr_ptr;
+ instr_ptr += sizeof(Dwarf_Small);
+
+ fp_base_op = (instr & 0xc0) >> 6;
+ if ((instr & 0xc0) == 0x00) {
+ opcode = instr; /* is really extended op */
+ fp_extended_op = (instr & (~(0xc0))) & 0xff;
+ } else {
+ opcode = instr & 0xc0; /* is base op */
+ fp_extended_op = 0;
+ }
+
+ fp_register = 0;
+ fp_offset = 0;
+ switch (opcode) {
+ case DW_CFA_advance_loc:
+ {
+ /* base op */
+ fp_offset = adv_pc = instr & DW_FRAME_INSTR_OFFSET_MASK;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_pc = adv_pc * code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_pc > search_pc_val);
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_pc;
+ }
+ break;
+ }
+
+ case DW_CFA_offset:
+ { /* base op */
+ reg_no =
+ (reg_num_type) (instr & DW_FRAME_INSTR_OFFSET_MASK);
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr = instr_ptr + leb128_length;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len =
+ factored_N_value * data_alignment_factor;
+
+ break;
+ }
+
+ case DW_CFA_restore:
+ { /* base op */
+ reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK);
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ fp_register = reg_no;
+
+ if (cie != NULL && cie->ci_initial_table != NULL)
+ localregtab[reg_no] =
+ cie->ci_initial_table->fr_reg[reg_no];
+ else if (!make_instr) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_MAKE_INSTR_NO_INIT);
+ }
+
+ break;
+ }
+ case DW_CFA_set_loc:
+ {
+ Dwarf_Addr new_loc = 0;
+
+ READ_UNALIGNED(dbg, new_loc, Dwarf_Addr,
+ instr_ptr, address_size);
+ instr_ptr += address_size;
+ if (new_loc != 0 && current_loc != 0) {
+ /* Pre-relocation or before current_loc is set the
+ test comparing new_loc and current_loc makes no
+ sense. Testing for non-zero (above) is a way
+ (fallible) to check that current_loc, new_loc
+ are already relocated. */
+ if (new_loc <= current_loc) {
+ /* Within a frame, address must increase.
+ Seemingly it has not. Seems to be an error. */
+
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_DF_NEW_LOC_LESS_OLD_LOC);
+ }
+ }
+
+ search_over = search_pc && (new_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = new_loc;
+ }
+ fp_offset = new_loc;
+ break;
+ }
+
+ case DW_CFA_advance_loc1:
+ {
+ fp_offset = adv_loc = *(Dwarf_Small *) instr_ptr;
+ instr_ptr += sizeof(Dwarf_Small);
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_advance_loc2:
+ {
+ READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned,
+ instr_ptr, sizeof(Dwarf_Half));
+ instr_ptr += sizeof(Dwarf_Half);
+ fp_offset = adv_loc;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_advance_loc4:
+ {
+ READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned,
+ instr_ptr, sizeof(Dwarf_ufixed));
+ instr_ptr += sizeof(Dwarf_ufixed);
+ fp_offset = adv_loc;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_offset_extended:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);;
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len = factored_N_value *
+ data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+ break;
+ }
+
+ case DW_CFA_restore_extended:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ if (cie != NULL && cie->ci_initial_table != NULL) {
+ localregtab[reg_no] = cie->ci_initial_table->fr_reg[reg_no];
+ } else {
+ if (!make_instr) {
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_DF_MAKE_INSTR_NO_INIT);
+ }
+ }
+
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_undefined:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ localregtab[reg_no].ru_is_off = 0;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register =
+ dbg->de_frame_undefined_value_number;
+ localregtab[reg_no].ru_offset_or_block_len = 0;
+
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_same_value:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ localregtab[reg_no].ru_is_off = 0;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register =
+ dbg->de_frame_same_value_number;
+ localregtab[reg_no].ru_offset_or_block_len = 0;
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_register:
+ {
+ Dwarf_Unsigned lreg;
+ reg_num_type reg_noA = 0;
+ reg_num_type reg_noB = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_noA = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count);
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_noB = (reg_num_type) lreg;
+
+ if (reg_noB > reg_count) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH);
+ }
+
+
+ localregtab[reg_noA].ru_is_off = 0;
+ localregtab[reg_noA].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_noA].ru_register = reg_noB;
+ localregtab[reg_noA].ru_offset_or_block_len = 0;
+
+ fp_register = reg_noA;
+ fp_offset = reg_noB;
+ break;
+ }
+
+ case DW_CFA_remember_state:
+ {
+ stack_table = (Dwarf_Frame)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1);
+ if (stack_table == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ for (i = 0; i < reg_count; i++)
+ stack_table->fr_reg[i] = localregtab[i];
+ stack_table->fr_cfa_rule = cfa_reg;
+
+ if (top_stack != NULL)
+ stack_table->fr_next = top_stack;
+ top_stack = stack_table;
+
+ break;
+ }
+
+ case DW_CFA_restore_state:
+ {
+ if (top_stack == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_POP_EMPTY_STACK);
+ }
+ stack_table = top_stack;
+ top_stack = stack_table->fr_next;
+
+ for (i = 0; i < reg_count; i++)
+ localregtab[i] = stack_table->fr_reg[i];
+ cfa_reg = stack_table->fr_cfa_rule;
+
+ dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME);
+ break;
+ }
+
+ case DW_CFA_def_cfa:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_register = reg_no;
+ cfa_reg.ru_offset_or_block_len = factored_N_value;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+ break;
+ }
+
+ case DW_CFA_def_cfa_register:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ cfa_reg.ru_register = reg_no;
+ /* Do NOT set ru_offset_or_block_len or ru_is_off here.
+ See dwarf2/3 spec. */
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_def_cfa_offset:
+ {
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_offset_or_block_len = factored_N_value;
+
+ fp_offset = factored_N_value;
+ break;
+ }
+ case DW_CFA_nop:
+ {
+ break;
+ }
+ /* DWARF3 ops begin here. */
+ case DW_CFA_def_cfa_expression:
+ {
+ /* A single DW_FORM_block representing a dwarf
+ expression. The form block establishes the way to
+ compute the CFA. */
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ cfa_reg.ru_is_off = 0; /* arbitrary */
+ cfa_reg.ru_value_type = DW_EXPR_EXPRESSION;
+ cfa_reg.ru_offset_or_block_len = block_len;
+ cfa_reg.ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+ instr_ptr += block_len;
+ }
+ break;
+ case DW_CFA_expression:
+ {
+ /* An unsigned leb128 value is the first operand (a
+ register number). The second operand is single
+ DW_FORM_block representing a dwarf expression. The
+ evaluator pushes the CFA on the evaluation stack
+ then evaluates the expression to compute the value
+ of the register contents. */
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ localregtab[lreg].ru_is_off = 0; /* arbitrary */
+ localregtab[lreg].ru_value_type = DW_EXPR_EXPRESSION;
+ localregtab[lreg].ru_offset_or_block_len = block_len;
+ localregtab[lreg].ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+ fp_register = reg_no;
+ instr_ptr += block_len;
+ }
+ break;
+ case DW_CFA_offset_extended_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a signed factored offset.
+ Identical to DW_CFA_offset_extended except the
+ secondoperand is signed */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_def_cfa_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a signed leb128 factored
+ offset. Identical to DW_CFA_def_cfa except that the
+ second operand is signed and factored. */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_register = reg_no;
+ cfa_reg.ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ {
+ /* The operand is a signed leb128 operand representing
+ a factored offset. Identical to
+ DW_CFA_def_cfa_offset excep the operand is signed
+ and factored. */
+
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_val_offset:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a factored unsigned offset.
+ Makes the register be a val_offset(N) rule with N =
+ factored_offset*data_alignment_factor. */
+
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
+ localregtab[reg_no].ru_offset_or_block_len =
+ factored_N_value * data_alignment_factor;
+
+ fp_offset = factored_N_value;
+ break;
+ }
+ case DW_CFA_val_offset_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a factored signed offset.
+ Makes the register be a val_offset(N) rule with N =
+ factored_offset*data_alignment_factor. */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
+ localregtab[reg_no].ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_offset = signed_factored_N_value;
+
+ }
+ break;
+ case DW_CFA_val_expression:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a DW_FORM_block representing a
+ DWARF expression. The rule for the register number
+ becomes a val_expression(E) rule. */
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ localregtab[lreg].ru_is_off = 0; /* arbitrary */
+ localregtab[lreg].ru_value_type = DW_EXPR_VAL_EXPRESSION;
+ localregtab[lreg].ru_offset_or_block_len = block_len;
+ localregtab[lreg].ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+
+ instr_ptr += block_len;
+ fp_register = reg_no;
+
+ }
+ break;
+
+ /* END DWARF3 new ops. */
+
+
+#ifdef DW_CFA_GNU_window_save
+ case DW_CFA_GNU_window_save:
+ {
+ /* no information: this just tells unwinder to restore
+ the window registers from the previous frame's
+ window save area */
+ break;
+ }
+#endif
+#ifdef DW_CFA_GNU_args_size
+ /* single uleb128 is the current arg area size in bytes. No
+ register exists yet to save this in */
+ case DW_CFA_GNU_args_size:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ break;
+ }
+#endif
+ default:
+ /* ERROR, we have an opcode we know nothing about. Memory
+ leak here, but an error like this is not supposed to
+ happen so we ignore the leak. These used to be ignored,
+ now we notice and report. */
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR);
+
+ }
+
+ if (make_instr) {
+ instr_count++;
+
+ curr_instr = (Dwarf_Frame_Op *)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME_OP, 1);
+ if (curr_instr == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ curr_instr->fp_base_op = fp_base_op;
+ curr_instr->fp_extended_op = fp_extended_op;
+ curr_instr->fp_register = fp_register;
+ curr_instr->fp_offset = fp_offset;
+ curr_instr->fp_instr_offset = fp_instr_offset;
+
+ curr_instr_item = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_instr_item == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ curr_instr_item->ch_item = curr_instr;
+ if (head_instr_chain == NULL)
+ head_instr_chain = tail_instr_chain = curr_instr_item;
+ else {
+ tail_instr_chain->ch_next = curr_instr_item;
+ tail_instr_chain = curr_instr_item;
+ }
+ }
+ }
+
+ /*
+ If frame instruction decoding was right we would stop exactly at
+ final_instr_ptr. */
+ if (instr_ptr > final_instr_ptr) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR);
+ }
+
+ /* Fill in the actual output table, the space the caller passed in. */
+ if (table != NULL) {
+
+ struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg;
+ struct Dwarf_Reg_Rule_s *t3reg = localregtab;
+ struct Dwarf_Reg_Rule_s *t3end = t3reg + reg_count;
+
+ table->fr_loc = current_loc;
+ for (; t3reg < t3end; t3reg++, t2reg++) {
+ *t2reg = *t3reg;
+ }
+
+ /* CONSTCOND */
+ /* Do not update the main table with the cfa_reg.
+ Just leave cfa_reg as cfa_reg. */
+ table->fr_cfa_rule = cfa_reg;
+ }
+
+ /* Dealloc anything remaining on stack. */
+ for (; top_stack != NULL;) {
+ stack_table = top_stack;
+ top_stack = top_stack->fr_next;
+ dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME);
+ }
+
+ if (make_instr) {
+ /* Allocate list of pointers to Dwarf_Frame_Op's. */
+ head_instr_block = (Dwarf_Frame_Op *)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME_BLOCK, instr_count);
+ if (head_instr_block == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ /*
+ Store pointers to Dwarf_Frame_Op's in this list and
+ deallocate the structs that chain the Dwarf_Frame_Op's. */
+ curr_instr_item = head_instr_chain;
+ for (i = 0; i < instr_count; i++) {
+ *(head_instr_block + i) =
+ *(Dwarf_Frame_Op *) curr_instr_item->ch_item;
+ dealloc_instr_item = curr_instr_item;
+ curr_instr_item = curr_instr_item->ch_next;
+ dwarf_dealloc(dbg, dealloc_instr_item->ch_item,
+ DW_DLA_FRAME_OP);
+ dwarf_dealloc(dbg, dealloc_instr_item, DW_DLA_CHAIN);
+ }
+ *ret_frame_instr = head_instr_block;
+
+ *returned_count = (Dwarf_Sword) instr_count;
+ } else {
+ *returned_count = 0;
+ }
+ free(localregtab);
+ return DW_DLV_OK;
+#undef ERROR_IF_REG_NUM_TOO_HIGH
+#undef SIMPLE_ERROR_RETURN
+}
+
+/* Depending on version, either read the return address register
+ as a ubyte or as an leb number.
+ The form of this value changed for DWARF3.
+*/
+Dwarf_Unsigned
+_dwarf_get_return_address_reg(Dwarf_Small * frame_ptr,
+ int version, unsigned long *size)
+{
+ Dwarf_Unsigned uvalue = 0;
+ Dwarf_Word leb128_length = 0;
+
+ if (version == 1) {
+ *size = 1;
+ uvalue = *(unsigned char *) frame_ptr;
+ return uvalue;
+ }
+ uvalue = _dwarf_decode_u_leb128(frame_ptr, &leb128_length);
+ *size = leb128_length;
+ return uvalue;
+}
+
+
+/* Trivial consumer function.
+*/
+int
+dwarf_get_cie_of_fde(Dwarf_Fde fde,
+ Dwarf_Cie * cie_returned, Dwarf_Error * error)
+{
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *cie_returned = fde->fd_cie;
+ return DW_DLV_OK;
+
+}
+
+int dwarf_get_cie_index(
+ Dwarf_Cie cie,
+ Dwarf_Signed* index,
+ Dwarf_Error* error )
+{
+ if( cie == NULL )
+ {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *index = cie->ci_index;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ For g++ .eh_frame fde and cie.
+ the cie id is different as the
+ definition of the cie_id in an fde
+ is the distance back from the address of the
+ value to the cie.
+ Or 0 if this is a true cie.
+ Non standard dwarf, designed this way to be
+ convenient at run time for an allocated
+ (mapped into memory as part of the running image) section.
+*/
+int
+dwarf_get_fde_list_eh(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_frame_eh_gnu,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_get_fde_list_internal(dbg,
+ cie_data,
+ cie_element_count,
+ fde_data,
+ fde_element_count,
+ dbg->de_debug_frame_eh_gnu.dss_data,
+ dbg->de_debug_frame_eh_gnu.dss_index,
+ dbg->de_debug_frame_eh_gnu.dss_size,
+ /* cie_id_value */ 0,
+ /* use_gnu_cie_calc= */ 1,
+ error);
+ return res;
+}
+
+
+
+/*
+ For standard dwarf .debug_frame
+ cie_id is -1 in a cie, and
+ is the section offset in the .debug_frame section
+ of the cie otherwise. Standard dwarf
+*/
+int
+dwarf_get_fde_list(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_get_fde_list_internal(dbg, cie_data,
+ cie_element_count,
+ fde_data,
+ fde_element_count,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ DW_CIE_ID,
+ /* use_gnu_cie_calc= */ 0,
+ error);
+
+ return res;
+}
+
+
+/*
+ Only works on dwarf sections, not eh_frame
+ Given a Dwarf_Die, see if it has a
+ DW_AT_MIPS_fde attribute and if so use that
+ to get an fde offset.
+ Then create a Dwarf_Fde to return thru the ret_fde pointer.
+ Also creates a cie (pointed at from the Dwarf_Fde).
+*/
+int
+dwarf_get_fde_for_die(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Fde * ret_fde, Dwarf_Error * error)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Unsigned fde_offset = 0;
+ Dwarf_Signed signdval = 0;
+ Dwarf_Fde new_fde = 0;
+ unsigned char *fde_ptr = 0;
+ unsigned char *cie_ptr = 0;
+ Dwarf_Unsigned cie_id = 0;
+
+ /* Fields for the current Cie being read. */
+ int res = 0;
+ int resattr = 0;
+ int sdatares = 0;
+
+ struct cie_fde_prefix_s prefix;
+ struct cie_fde_prefix_s prefix_c;
+
+ if (die == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ resattr = dwarf_attr(die, DW_AT_MIPS_fde, &attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ /* why is this formsdata? FIX */
+ sdatares = dwarf_formsdata(attr, &signdval, error);
+ if (sdatares != DW_DLV_OK) {
+ return sdatares;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ fde_offset = signdval;
+ fde_ptr = (dbg->de_debug_frame.dss_data + fde_offset);
+
+
+ /* First read in the 'common prefix' to figure out what * we are to
+ do with this entry. */
+ memset(&prefix_c, 0, sizeof(prefix_c));
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg, fde_ptr,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ &prefix,
+ error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ return res;
+ fde_ptr = prefix.cf_addr_after_prefix;
+ cie_id = prefix.cf_cie_id;
+ /* Pass NULL, not section pointer, for 3rd argument.
+ de_debug_frame.dss_data has no eh_frame relevance. */
+ res = dwarf_create_fde_from_after_start(dbg, &prefix,
+ (Dwarf_Small *) NULL,
+ fde_ptr,
+ /* use_gnu_cie_calc= */ 0,
+ /* Dwarf_Cie = */ 0,
+ &new_fde, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ /* DW_DLV_OK */
+
+ /* now read the cie corresponding to the fde */
+ cie_ptr = new_fde->fd_section_ptr + cie_id;
+ res = dwarf_read_cie_fde_prefix(dbg, cie_ptr,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ &prefix_c, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ return res;
+
+ cie_ptr = prefix_c.cf_addr_after_prefix;
+ cie_id = prefix_c.cf_cie_id;
+
+ if (cie_id == DW_CIE_ID) {
+ int res2 = 0;
+ Dwarf_Cie new_cie = 0;
+
+ /* Pass NULL, not section pointer, for 3rd argument.
+ de_debug_frame.dss_data has no eh_frame relevance. */
+ res2 = dwarf_create_cie_from_after_start(dbg,
+ &prefix_c,
+ (Dwarf_Small *) NULL,
+ cie_ptr,
+ /* cie_count= */ 0,
+ /* use_gnu_cie_calc= */
+ 0, &new_cie, error);
+ if (res2 == DW_DLV_ERROR) {
+ dwarf_dealloc(dbg, new_fde, DW_DLA_FDE);
+ return res;
+ } else if (res2 == DW_DLV_NO_ENTRY) {
+ dwarf_dealloc(dbg, new_fde, DW_DLA_FDE);
+ return res;
+ }
+ new_fde->fd_cie = new_cie;
+ } else {
+ _dwarf_error(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_fde = new_fde;
+ return DW_DLV_OK;
+}
+
+/* A dwarf consumer operation, see the consumer library documentation.
+*/
+int
+dwarf_get_fde_range(Dwarf_Fde fde,
+ Dwarf_Addr * low_pc,
+ Dwarf_Unsigned * func_length,
+ Dwarf_Ptr * fde_bytes,
+ Dwarf_Unsigned * fde_byte_length,
+ Dwarf_Off * cie_offset,
+ Dwarf_Signed * cie_index,
+ Dwarf_Off * fde_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ /* We have always already done the section load here, so no need to
+ load the section. We did the section load in order to create the
+ Dwarf_Fde pointer passed in here. */
+
+
+ if (low_pc != NULL)
+ *low_pc = fde->fd_initial_location;
+ if (func_length != NULL)
+ *func_length = fde->fd_address_range;
+ if (fde_bytes != NULL)
+ *fde_bytes = fde->fd_fde_start;
+ if (fde_byte_length != NULL)
+ *fde_byte_length = fde->fd_length;
+ if (cie_offset != NULL)
+ *cie_offset = fde->fd_cie_offset;
+ if (cie_index != NULL)
+ *cie_index = fde->fd_cie_index;
+ if (fde_offset != NULL)
+ *fde_offset = fde->fd_fde_start - fde->fd_section_ptr;
+
+ return DW_DLV_OK;
+}
+
+/* IRIX specific function. The exception tables
+ have C++ destructor information and are
+ at present undocumented. */
+int
+dwarf_get_fde_exception_info(Dwarf_Fde fde,
+ Dwarf_Signed *
+ offset_into_exception_tables,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *offset_into_exception_tables =
+ fde->fd_offset_into_exception_tables;
+ return DW_DLV_OK;
+}
+
+
+/* A consumer code function.
+ Given a CIE pointer, return the normal CIE data thru
+ pointers.
+ Special augmentation data is not returned here.
+*/
+int
+dwarf_get_cie_info(Dwarf_Cie cie,
+ Dwarf_Unsigned * bytes_in_cie,
+ Dwarf_Small * ptr_to_version,
+ char **augmenter,
+ Dwarf_Unsigned * code_alignment_factor,
+ Dwarf_Signed * data_alignment_factor,
+ Dwarf_Half * return_address_register,
+ Dwarf_Ptr * initial_instructions,
+ Dwarf_Unsigned * initial_instructions_length,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cie->ci_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (ptr_to_version != NULL)
+ *ptr_to_version = cie->ci_cie_version_number;
+ if (augmenter != NULL)
+ *augmenter = cie->ci_augmentation;
+ if (code_alignment_factor != NULL)
+ *code_alignment_factor = cie->ci_code_alignment_factor;
+ if (data_alignment_factor != NULL)
+ *data_alignment_factor = cie->ci_data_alignment_factor;
+ if (return_address_register != NULL)
+ *return_address_register = cie->ci_return_address_register;
+ if (initial_instructions != NULL)
+ *initial_instructions = cie->ci_cie_instr_start;
+ if (initial_instructions_length != NULL) {
+ *initial_instructions_length = cie->ci_length +
+ cie->ci_length_size +
+ cie->ci_extension_size -
+ (cie->ci_cie_instr_start - cie->ci_cie_start);
+
+ }
+ *bytes_in_cie = (cie->ci_length);
+ return (DW_DLV_OK);
+}
+
+/* Return the register rules for all registers at a given pc.
+*/
+static int
+_dwarf_get_fde_info_for_a_pc_row(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Frame table,
+ Dwarf_Half cfa_reg_col_num,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Cie cie = 0;
+ int dw_err = 0;
+ Dwarf_Sword icount = 0;
+ int res = 0;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (pc_requested < fde->fd_initial_location ||
+ pc_requested >=
+ fde->fd_initial_location + fde->fd_address_range) {
+ _dwarf_error(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE);
+ return (DW_DLV_ERROR);
+ }
+
+ cie = fde->fd_cie;
+ if (cie->ci_initial_table == NULL) {
+ cie->ci_initial_table = _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1);
+
+ if (cie->ci_initial_table == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ _dwarf_init_regrule_table(cie->ci_initial_table->fr_reg,
+ dbg->de_frame_reg_rules_entry_count,
+ dbg->de_frame_rule_initial_value);
+ _dwarf_init_regrule_table(&cie->ci_initial_table->fr_cfa_rule,
+ 1, dbg->de_frame_rule_initial_value);
+ res = _dwarf_exec_frame_instr( /* make_instr= */ false,
+ /* ret_frame_instr= */ NULL,
+ /* search_pc */ false,
+ /* search_pc_val */ 0,
+ /* location */ 0,
+ cie->ci_cie_instr_start,
+ cie->ci_cie_instr_start + (cie->ci_length +
+ cie->ci_length_size +
+ cie->ci_extension_size -
+ (cie->ci_cie_instr_start -
+ cie->ci_cie_start)),
+ cie->ci_initial_table, cie, dbg,
+ cfa_reg_col_num, &icount,
+ &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ }
+
+ {
+ Dwarf_Small *instr_end = fde->fd_fde_instr_start +
+ fde->fd_length +
+ fde->fd_length_size +
+ fde->fd_extension_size - (fde->fd_fde_instr_start -
+ fde->fd_fde_start);
+
+ res = _dwarf_exec_frame_instr( /* make_instr= */ false,
+ /* ret_frame_instr= */ NULL,
+ /* search_pc */ true,
+ /* search_pc_val */ pc_requested,
+ fde->fd_initial_location,
+ fde->fd_fde_instr_start,
+ instr_end,
+ table,
+ cie, dbg,
+ cfa_reg_col_num, &icount,
+ &dw_err);
+ }
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+
+ return DW_DLV_OK;
+}
+
+/* A consumer call for efficiently getting the register info
+ for all registers in one call.
+
+ The output table rules array is size DW_REG_TABLE_SIZE.
+ The frame info rules array in fde_table is of size
+ DW_REG_TABLE_SIZE too.
+
+ This interface really only works well with MIPS/IRIX
+ where DW_FRAME_CFA_COL is zero (in that case it's safe).
+
+ It is also restricted to the case where
+ DW_REG_TABLE_SIZE == DW_FRAME_LAST_REG_NUM ==
+ dbg->de_frame_reg_rules_entry_count (true for MIPS/IRIX).
+ If this condition is not met calling this routine can result in
+ incorrect output or in memory corruption.
+
+ It is much better to use dwarf_get_fde_info_for_all_regs3()
+ instead of this interface.
+*/
+int
+dwarf_get_fde_info_for_all_regs(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Regtable * reg_table,
+ Dwarf_Addr * row_pc,
+ Dwarf_Error * error)
+{
+
+ /* Table size: DW_REG_TABLE_SIZE */
+ struct Dwarf_Frame_s fde_table;
+ Dwarf_Sword i = 0;
+ struct Dwarf_Reg_Rule_s *rule = NULL;
+ struct Dwarf_Regtable_Entry_s *out_rule = NULL;
+ int res = 0;
+ Dwarf_Debug dbg = 0;
+
+ /* For this interface the size is fixed at compile time. */
+ int output_table_real_data_size = DW_REG_TABLE_SIZE;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+ if (res != DW_DLV_OK)
+ return res;
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
+ &fde_table, dbg->de_frame_cfa_col_number, error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ out_rule = &reg_table->rules[0];
+ rule = &fde_table.fr_reg[0];
+ for (i = 0; i < output_table_real_data_size;
+ i++, ++out_rule, ++rule) {
+ out_rule->dw_offset_relevant = rule->ru_is_off;
+ out_rule->dw_value_type = rule->ru_value_type;
+ out_rule->dw_regnum = rule->ru_register;
+ out_rule->dw_offset = rule->ru_offset_or_block_len;
+ }
+ for (; i < DW_REG_TABLE_SIZE; ++i, ++out_rule) {
+ out_rule->dw_offset_relevant = 0;
+ out_rule->dw_value_type = DW_EXPR_OFFSET;
+ out_rule->dw_regnum = dbg->de_frame_undefined_value_number;
+ out_rule->dw_offset = 0;
+ }
+
+ /* The test is just in case it's not inside the table. For non-MIPS
+ it could be outside the table and that is just fine, it was
+ really a mistake to put it in the table in 1993. */
+ /* CONSTCOND */
+ if (dbg->de_frame_cfa_col_number < DW_REG_TABLE_SIZE) {
+ out_rule = &reg_table->rules[dbg->de_frame_cfa_col_number];
+ out_rule->dw_offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+ out_rule->dw_value_type = fde_table.fr_cfa_rule.ru_value_type;
+ out_rule->dw_regnum = fde_table.fr_cfa_rule.ru_register;
+ out_rule->dw_offset =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ }
+
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+/* A consumer call for efficiently getting the register info
+ for all registers in one call.
+
+ The output table rules array is size output_table_real_data_size.
+ (normally DW_REG_TABLE_SIZE).
+ The frame info rules array in fde_table is normally of size
+ DW_FRAME_LAST_REG_NUM.
+*/
+int
+dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Regtable3 * reg_table,
+ Dwarf_Addr * row_pc,
+ Dwarf_Error * error)
+{
+
+ struct Dwarf_Frame_s fde_table;
+ Dwarf_Sword i = 0;
+ int res = 0;
+ struct Dwarf_Reg_Rule_s *rule = NULL;
+ struct Dwarf_Regtable_Entry3_s *out_rule = NULL;
+ Dwarf_Debug dbg = 0;
+ int output_table_real_data_size = reg_table->rt3_reg_table_size;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ output_table_real_data_size =
+ MIN(output_table_real_data_size,
+ dbg->de_frame_reg_rules_entry_count);
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
+ &fde_table,
+ dbg->de_frame_cfa_col_number,
+ error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ out_rule = &reg_table->rt3_rules[0];
+ rule = &fde_table.fr_reg[0];
+ for (i = 0; i < output_table_real_data_size;
+ i++, ++out_rule, ++rule) {
+ out_rule->dw_offset_relevant = rule->ru_is_off;
+ out_rule->dw_value_type = rule->ru_value_type;
+ out_rule->dw_regnum = rule->ru_register;
+ out_rule->dw_offset_or_block_len = rule->ru_offset_or_block_len;
+ out_rule->dw_block_ptr = rule->ru_block;
+ }
+ for (; i < reg_table->rt3_reg_table_size; i++, ++out_rule) {
+ out_rule->dw_offset_relevant = 0;
+ out_rule->dw_value_type = DW_EXPR_OFFSET;
+ out_rule->dw_regnum = dbg->de_frame_undefined_value_number;
+ out_rule->dw_offset_or_block_len = 0;
+ out_rule->dw_block_ptr = 0;
+ }
+ reg_table->rt3_cfa_rule.dw_offset_relevant =
+ fde_table.fr_cfa_rule.ru_is_off;
+ reg_table->rt3_cfa_rule.dw_value_type =
+ fde_table.fr_cfa_rule.ru_value_type;
+ reg_table->rt3_cfa_rule.dw_regnum =
+ fde_table.fr_cfa_rule.ru_register;
+ reg_table->rt3_cfa_rule.dw_offset_or_block_len =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ reg_table->rt3_cfa_rule.dw_block_ptr =
+ fde_table.fr_cfa_rule.ru_block;
+
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+
+/* Gets the register info for a single register at a given PC value
+ for the FDE specified.
+
+ This is the old MIPS interface and should no longer be used.
+ Use dwarf_get_fde_info_for_reg3() instead.
+*/
+int
+dwarf_get_fde_info_for_reg(Dwarf_Fde fde,
+ Dwarf_Half table_column,
+ Dwarf_Addr pc_requested,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset,
+ Dwarf_Addr * row_pc, Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+ Dwarf_Debug dbg = 0;
+ int output_table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+ output_table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+ if (res != DW_DLV_OK)
+ return res;
+
+ if (table_column >= output_table_real_data_size) {
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res =
+ _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number, error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (fde_table.fr_reg[table_column].ru_value_type != DW_EXPR_OFFSET) {
+ /* The problem here is that this interface cannot deal with
+ other sorts of (newer) dwarf frame values. Code must
+ use dwarf_get_fde_info_for_reg3() to get these
+ values correctly. We error rather than return
+ misleading incomplete data. */
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(NULL, error,
+ DW_DLE_FRAME_REGISTER_UNREPRESENTABLE);
+ return (DW_DLV_ERROR);
+ }
+ if(table_column == dbg->de_frame_cfa_col_number) {
+ if (register_num != NULL)
+ *register_num = fde_table.fr_cfa_rule.ru_register;
+ if (offset != NULL)
+ *offset = fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+ *offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+
+ } else {
+ if (register_num != NULL)
+ *register_num = fde_table.fr_reg[table_column].ru_register;
+ if (offset != NULL)
+ *offset = fde_table.fr_reg[table_column].ru_offset_or_block_len;
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+
+ *offset_relevant = fde_table.fr_reg[table_column].ru_is_off;
+ }
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+/* In this interface, table_column of DW_FRAME_CFA_COL
+ is not meaningful.
+ Use dwarf_get_fde_info_for_cfa_reg3() to get the CFA.
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init()
+ (DW_FRAME_CFA_COL3 is a sensible column to use).
+*/
+int
+dwarf_get_fde_info_for_reg3(Dwarf_Fde fde,
+ Dwarf_Half table_column,
+ Dwarf_Addr pc_requested,
+ Dwarf_Small * value_type,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset_or_block_len,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Addr * row_pc_out,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+
+ Dwarf_Debug dbg = 0;
+ int table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+ table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ table_real_data_size, error);
+ if (res != DW_DLV_OK)
+ return res;
+ if (table_column >= table_real_data_size) {
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number,
+ error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (register_num != NULL)
+ *register_num = fde_table.fr_reg[table_column].ru_register;
+ if (offset_or_block_len != NULL)
+ *offset_or_block_len =
+ fde_table.fr_reg[table_column].ru_offset_or_block_len;
+ if (row_pc_out != NULL)
+ *row_pc_out = fde_table.fr_loc;
+ if (block_ptr)
+ *block_ptr = fde_table.fr_reg[table_column].ru_block;
+
+ /* Without value_type the data cannot be understood, so we insist
+ on it being present, we don't test it. */
+ *value_type = fde_table.fr_reg[table_column].ru_value_type;
+ *offset_relevant = (fde_table.fr_reg[table_column].ru_is_off);
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+
+}
+
+/* For latest DWARF, this is the preferred interface.
+ It more portably deals with the CFA by not
+ making the CFA a column number, which means
+ DW_FRAME_CFA_COL3 becomes, like DW_CFA_SAME_VALUE,
+ a special value, not something one uses as an index.
+
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init()
+ (DW_FRAME_CFA_COL3 is a sensible column to use, and
+ is the default unless '--enable-oldframecol'
+ is used to configure libdwarf). */
+int
+dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Small * value_type,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset_or_block_len,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Addr * row_pc_out,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+ Dwarf_Debug dbg = 0;
+
+ int table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ table_real_data_size, error);
+ if (res != DW_DLV_OK)
+ return res;
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number,error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (register_num != NULL)
+ *register_num = fde_table.fr_cfa_rule.ru_register;
+ if (offset_or_block_len != NULL)
+ *offset_or_block_len =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ if (row_pc_out != NULL)
+ *row_pc_out = fde_table.fr_loc;
+ if (block_ptr)
+ *block_ptr = fde_table.fr_cfa_rule.ru_block;
+
+ /* Without value_type the data cannot be understood, so we insist
+ on it being present, we don't test it. */
+ *value_type = fde_table.fr_cfa_rule.ru_value_type;
+ *offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Return pointer to the instructions in the dwarf
+ fde.
+*/
+int
+dwarf_get_fde_instr_bytes(Dwarf_Fde inFde, Dwarf_Ptr * outinstraddr,
+ Dwarf_Unsigned * outaddrlen,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned len = 0;
+ unsigned char *instrs = 0;
+ Dwarf_Debug dbg = 0;
+
+ if (inFde == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = inFde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ instrs = inFde->fd_fde_instr_start;
+
+ len = (inFde->fd_fde_start + inFde->fd_length +
+ inFde->fd_length_size + inFde->fd_extension_size) - instrs;
+
+ *outinstraddr = instrs;
+ *outaddrlen = len;
+ return DW_DLV_OK;
+}
+
+/* Allows getting an fde from its table via an index.
+ With more error checking than simply indexing oneself.
+*/
+int
+dwarf_get_fde_n(Dwarf_Fde * fde_data,
+ Dwarf_Unsigned fde_index,
+ Dwarf_Fde * returned_fde, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Signed fdecount = 0;
+
+ if (fde_data == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ FDE_NULL_CHECKS_AND_SET_DBG(*fde_data, dbg);
+ /* Assumes fde_data table has at least one entry. */
+ fdecount = fde_data[0]->fd_is_eh?
+ dbg->de_fde_count_eh:dbg->de_fde_count;
+ if (fde_index >= fdecount) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ *returned_fde = (*(fde_data + fde_index));
+ return DW_DLV_OK;
+}
+
+
+/*
+ Lopc and hipc are extensions to the interface to
+ return the range of addresses that are described
+ by the returned fde.
+*/
+int
+dwarf_get_fde_at_pc(Dwarf_Fde * fde_data,
+ Dwarf_Addr pc_of_interest,
+ Dwarf_Fde * returned_fde,
+ Dwarf_Addr * lopc,
+ Dwarf_Addr * hipc, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = NULL;
+ Dwarf_Fde fde = NULL;
+ Dwarf_Fde entryfde = NULL;
+ Dwarf_Signed fdecount = 0;
+
+ if (fde_data == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Assumes fde_data table has at least one entry. */
+ entryfde = *fde_data;
+ FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg);
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ fdecount = entryfde->fd_is_eh?
+ dbg->de_fde_count_eh:dbg->de_fde_count;
+ {
+ /* The fde's are sorted by their addresses. Binary search to
+ find correct fde. */
+ Dwarf_Signed low = 0;
+ Dwarf_Signed high = fdecount - 1L;
+ Dwarf_Signed middle = 0;
+ Dwarf_Fde cur_fde;
+
+ while (low <= high) {
+ middle = (low + high) / 2;
+ cur_fde = fde_data[middle];
+ if (pc_of_interest < cur_fde->fd_initial_location) {
+ high = middle - 1;
+ } else if (pc_of_interest >=
+ (cur_fde->fd_initial_location +
+ cur_fde->fd_address_range)) {
+ low = middle + 1;
+ } else {
+ fde = fde_data[middle];
+ break;
+ }
+ }
+ }
+
+ if (fde) {
+ if (lopc != NULL)
+ *lopc = fde->fd_initial_location;
+ if (hipc != NULL)
+ *hipc =
+ fde->fd_initial_location + fde->fd_address_range - 1;
+ *returned_fde = fde;
+ return (DW_DLV_OK);
+ }
+
+ return (DW_DLV_NO_ENTRY);
+}
+
+
+/* Expands a single frame instruction block
+ from a specific cie
+ into a n array of Dwarf_Frame_Op-s.
+ This depends on having the cfa column set sensibly.
+
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init() unless you are using
+ the old MIPS frame interfaces (in which case the default
+ will be ok). (DW_FRAME_CFA_COL3 is a sensible column to use ).
+*/
+int
+dwarf_expand_frame_instructions(Dwarf_Cie cie,
+ Dwarf_Ptr instruction,
+ Dwarf_Unsigned i_length,
+ Dwarf_Frame_Op ** returned_op_list,
+ Dwarf_Signed * returned_op_count,
+ Dwarf_Error * error)
+{
+ Dwarf_Sword instr_count;
+ int res = DW_DLV_ERROR;
+ int dw_err;
+ Dwarf_Debug dbg = 0;
+
+ if (cie == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cie->ci_dbg;
+
+ if (returned_op_list == 0 || returned_op_count == 0) {
+ _dwarf_error(dbg, error, DW_DLE_RET_OP_LIST_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* The cast to Dwarf_Ptr may get a compiler warning, but it is safe
+ as it is just an i_length offset from 'instruction' itself. A
+ caller has made a big mistake if the result is not a valid
+ pointer. */
+ res = _dwarf_exec_frame_instr( /* make_instr= */ true,
+ returned_op_list,
+ /* search_pc */ false,
+ /* search_pc_val */ 0,
+ /* location */ 0,
+ instruction,
+ (Dwarf_Ptr)((char *)instruction + i_length),
+ /* Dwarf_Frame */ NULL,
+ cie,
+ dbg,
+ dbg->de_frame_cfa_col_number, &instr_count,
+ &dw_err);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ }
+ return (res);
+ }
+
+ *returned_op_count = instr_count;
+ return DW_DLV_OK;
+}
+
+
+/* Used by dwarfdump -v to print offsets, for debugging
+ dwarf info.
+ The dwarf_ version is preferred over the obsolete _dwarf version.
+ _dwarf version kept for compatibility.
+*/
+/* ARGSUSED 4 */
+int
+_dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde,
+ Dwarf_Off * fde_off, Dwarf_Off * cie_off,
+ Dwarf_Error * err)
+{
+ return dwarf_fde_section_offset(dbg,in_fde,fde_off,
+ cie_off,err);
+}
+/* ARGSUSED 4 */
+int
+dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde,
+ Dwarf_Off * fde_off, Dwarf_Off * cie_off,
+ Dwarf_Error * err)
+{
+ char *start = 0;
+ char *loc = 0;
+
+
+
+ start = (char *) in_fde->fd_section_ptr;
+ loc = (char *) in_fde->fd_fde_start;
+
+ *fde_off = (loc - start);
+ *cie_off = in_fde->fd_cie_offset;
+ return DW_DLV_OK;
+}
+
+/* Used by dwarfdump -v to print offsets, for debugging
+ dwarf info.
+ The dwarf_ version is preferred over the obsolete _dwarf version.
+ _dwarf version kept for compatibility.
+*/
+/* ARGSUSED 4 */
+int
+_dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie,
+ Dwarf_Off * cie_off, Dwarf_Error * err)
+{
+ return dwarf_cie_section_offset(dbg,in_cie,cie_off,err);
+}
+/* ARGSUSED 4 */
+int
+dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie,
+ Dwarf_Off * cie_off, Dwarf_Error * err)
+{
+ char *start = 0;
+ char *loc = 0;
+
+ start = (char *) in_cie->ci_section_ptr;
+ loc = (char *) in_cie->ci_cie_start;
+
+ *cie_off = (loc - start);
+ return DW_DLV_OK;
+}
+
+/* Returns a pointer to target-specific augmentation data thru augdata
+ and returns the length of the data thru augdata_len.
+
+ It's up to the consumer code to know how to interpret the bytes
+ of target-specific data (endian issues apply too, these
+ are just raw bytes pointed to).
+ See Linux Standard Base Core Specification version 3.0 for
+ the details on .eh_frame info.
+
+ Returns DW_DLV_ERROR if fde is NULL or some other serious
+ error.
+ Returns DW_DLV_NO_ENTRY if there is no target-specific
+ augmentation data.
+
+ The bytes pointed to are in the Dwarf_Cie, and as long as that
+ is valid the bytes are there. No 'dealloc' call is needed
+ for the bytes.
+*/
+int
+dwarf_get_cie_augmentation_data(Dwarf_Cie cie,
+ Dwarf_Small ** augdata,
+ Dwarf_Unsigned * augdata_len,
+ Dwarf_Error * error)
+{
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (cie->ci_gnu_eh_augmentation_len == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ *augdata = (Dwarf_Small *) (cie->ci_gnu_eh_augmentation_bytes);
+ *augdata_len = cie->ci_gnu_eh_augmentation_len;
+ return DW_DLV_OK;
+}
+
+
+/* Returns a pointer to target-specific augmentation data thru augdata
+ and returns the length of the data thru augdata_len.
+
+ It's up to the consumer code to know how to interpret the bytes
+ of target-specific data (endian issues apply too, these
+ are just raw bytes pointed to).
+ See Linux Standard Base Core Specification version 3.0 for
+ the details on .eh_frame info.
+
+ Returns DW_DLV_ERROR if fde is NULL or some other serious
+ error.
+ Returns DW_DLV_NO_ENTRY if there is no target-specific
+ augmentation data.
+
+ The bytes pointed to are in the Dwarf_Fde, and as long as that
+ is valid the bytes are there. No 'dealloc' call is needed
+ for the bytes.
+
+*/
+int
+dwarf_get_fde_augmentation_data(Dwarf_Fde fde,
+ Dwarf_Small * *augdata,
+ Dwarf_Unsigned * augdata_len,
+ Dwarf_Error * error)
+{
+ Dwarf_Cie cie = 0;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ cie = fde->fd_cie;
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (cie->ci_gnu_eh_augmentation_len == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ *augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes;
+ *augdata_len = fde->fd_gnu_eh_augmentation_len;
+ return DW_DLV_OK;
+}
+
+
+/* Initialize with same_value , a value which makes sense
+ for IRIX/MIPS.
+ The correct value to use is ABI dependent.
+ For register-windows machines most
+ or all registers should get DW_FRAME_UNDEFINED_VAL as the
+ correct initial value.
+ Some think DW_FRAME_UNDEFINED_VAL is always the
+ right value.
+
+ For some ABIs a setting which varies by register
+ would be more appropriate.
+
+ FIXME. */
+
+static void
+_dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg,
+ int last_reg_num, int initial_value)
+{
+ struct Dwarf_Reg_Rule_s *t1end = t1reg + last_reg_num;
+
+ for (; t1reg < t1end; t1reg++) {
+ t1reg->ru_is_off = 0;
+ t1reg->ru_value_type = DW_EXPR_OFFSET;
+ t1reg->ru_register = initial_value;
+ t1reg->ru_offset_or_block_len = 0;
+ t1reg->ru_block = 0;
+ }
+}
+
+#if 0
+/* Used solely for debugging libdwarf. */
+static void
+dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule)
+{
+ printf
+ ("%s type %s (" DW_PR_DUx "), is_off "
+ DW_PR_DUu " reg " DW_PR_DUu " offset " DW_PR_DUx " blockp "
+ DW_PR_DUx "\n",
+ msg,
+ (reg_rule->ru_value_type == DW_EXPR_OFFSET) ?
+ "DW_EXPR_OFFSET" :
+ (reg_rule->ru_value_type == DW_EXPR_VAL_OFFSET) ?
+ "DW_EXPR_VAL_OFFSET" :
+ (reg_rule->ru_value_type == DW_EXPR_VAL_EXPRESSION) ?
+ "DW_EXPR_VAL_EXPRESSION" :
+ (reg_rule->ru_value_type == DW_EXPR_EXPRESSION) ?
+ "DW_EXPR_EXPRESSION" : "Unknown",
+ (Dwarf_Unsigned) reg_rule->ru_value_type,
+ (Dwarf_Unsigned) reg_rule->ru_is_off,
+ (Dwarf_Unsigned) reg_rule->ru_register,
+ (Dwarf_Unsigned) reg_rule->ru_offset_or_block_len,
+ (Dwarf_Unsigned) reg_rule->ru_block);
+ return;
+}
+#endif
+
+/* This allows consumers to set the 'initial value' so that
+ an ISA/ABI specific default can be used, dynamically,
+ at run time. Useful for dwarfdump and non-MIPS architectures..
+ The value defaults to one of
+ DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE
+ but dwarfdump can dump multiple ISA/ABI objects so
+ we may want to get this set to what the ABI says is correct.
+
+ Returns the value that was present before we changed it here.
+*/
+Dwarf_Half
+dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_rule_initial_value;
+ dbg->de_frame_rule_initial_value = value;
+ return orig;
+}
+
+/* The following spelling for backwards compatibility. */
+Dwarf_Half
+dwarf_set_frame_rule_inital_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ return dwarf_set_frame_rule_initial_value(dbg,value);
+}
+
+/* This allows consumers to set the array size of the reg rules
+ table so that
+ an ISA/ABI specific value can be used, dynamically,
+ at run time. Useful for non-MIPS archtectures.
+ The value defaults to DW_FRAME_LAST_REG_NUM.
+ but dwarfdump can dump multiple ISA/ABI objects so
+ consumers want to get this set to what the ABI says is correct.
+
+ Returns the value that was present before we changed it here.
+*/
+
+Dwarf_Half
+dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_reg_rules_entry_count;
+ dbg->de_frame_reg_rules_entry_count = value;
+ return orig;
+}
+/* This allows consumers to set the CFA register value
+ * so that an ISA/ABI specific value can be used, dynamically,
+ * at run time. Useful for non-MIPS archtectures.
+ * The value defaults to DW_FRAME_CFA_COL3 and should be
+ * higher than any real register in the ABI.
+ * Dwarfdump can dump multiple ISA/ABI objects so
+ * consumers want to get this set to what the ABI says is correct.
+
+ * Returns the value that was present before we changed it here.
+ * */
+
+Dwarf_Half
+dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_cfa_col_number;
+ dbg->de_frame_cfa_col_number = value;
+ return orig;
+}
+/* Similar to above, but for the other crucial fields for frames. */
+Dwarf_Half
+dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_same_value_number;
+ dbg->de_frame_same_value_number = value;
+ return orig;
+}
+Dwarf_Half
+dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_same_value_number;
+ dbg->de_frame_undefined_value_number = value;
+ return orig;
+}
+
+
+
+
+
+static int
+dwarf_initialize_fde_table(Dwarf_Debug dbg,
+ struct Dwarf_Frame_s *fde_table,
+ unsigned table_real_data_size,
+ Dwarf_Error * error)
+{
+ unsigned entry_size = sizeof(struct Dwarf_Frame_s);
+
+ fde_table->fr_loc = 0;
+ fde_table->fr_reg_count = table_real_data_size;
+ fde_table->fr_next = 0;
+
+ fde_table->fr_reg = (struct Dwarf_Reg_Rule_s *)
+ calloc(entry_size, table_real_data_size);
+ if (fde_table->fr_reg == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+
+}
+static void
+dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table)
+{
+ free(fde_table->fr_reg);
+ fde_table->fr_reg_count = 0;
+ fde_table->fr_reg = 0;
+}
+
+
+/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR.
+*/
+int
+_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame)
+{
+ struct Dwarf_Frame_s *fp = frame;
+
+ if (!dbg) {
+ return DW_DLV_ERROR;
+ }
+
+ fp->fr_reg = calloc(dbg->de_frame_reg_rules_entry_count,
+ sizeof(struct Dwarf_Reg_Rule_s));
+ if (!fp->fr_reg) {
+ return DW_DLV_ERROR;
+ }
+ fp->fr_reg_count = dbg->de_frame_reg_rules_entry_count;
+ return DW_DLV_OK;
+}
+
+void
+_dwarf_frame_destructor(void *frame)
+{
+ struct Dwarf_Frame_s *fp = frame;
+
+ if (fp->fr_reg) {
+ free(fp->fr_reg);
+ }
+ fp->fr_reg = 0;
+ fp->fr_reg_count = 0;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame.h b/usr/src/lib/libdwarf/common/dwarf_frame.h
new file mode 100644
index 0000000000..ceb686335b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame.h
@@ -0,0 +1,421 @@
+/*
+
+ Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* The dwarf 2.0 standard dictates that only the following
+ * fields can be read when an unexpected augmentation string
+ * (in the cie) is encountered: CIE length, CIE_id, version and
+ * augmentation; FDE: length, CIE pointer, initial location and
+ * address range. Unfortunately, with the above restrictions, it
+ * is impossible to read the instruction table from a CIE or a FDE
+ * when a new augmentation string is encountered.
+ * To fix this problem, the following layout is used, if the
+ * augmentation string starts with the string "z".
+ * CIE FDE
+ * length length
+ * CIE_id CIE_pointer
+ * version initial_location
+ * augmentation address_range
+ * length_of_augmented_fields (*NEW*)
+ * code_alignment_factor Any new fields as necessary
+ * data_alignment_factor instruction_table
+ * return_address
+ * length_of_augmented fields
+ * Any new fields as necessary
+ * initial_instructions
+ *
+ * The type of all the old data items are the same as what is
+ * described in dwarf 2.0 standard. The length_of_augmented_fields
+ * is an LEB128 data item that denotes the size (in bytes) of
+ * the augmented fields (not including the size of
+ * "length_of_augmented_fields" itself).
+
+ * Handling of cie augmentation strings is necessarly a heuristic.
+ * See dwarf_frame.c for the currently known augmentation strings.
+
+
+ ---START SGI-ONLY COMMENT:
+ * SGI-IRIX versions of cie or fde were intended to use "z1", "z2" as the
+ * augmenter strings if required for new augmentation.
+ * However, that never happened (as of March 2005).
+ *
+ * The fde's augmented by the string "z" have a new field
+ * (signed constant, 4 byte field)
+ * called offset_into_exception_tables, following the
+ * length_of_augmented field. This field contains an offset
+ * into the "_MIPS_eh_region", which describes
+ * the IRIX CC exception handling tables.
+ ---END SGI-ONLY COMMENT
+
+
+ * GNU .eh_frame has an augmentation string of z[RLP]* (gcc 3.4)
+ * The similarity to IRIX 'z' (and proposed but never
+ * implemented IRIX z1, z2 etc) was confusing things.
+ * If the section is .eh_frame then 'z' means GNU exception
+ * information 'Augmentation Data' not IRIX 'z'.
+ * See The Linux Standard Base Core Specification version 3.0
+ */
+
+#define DW_DEBUG_FRAME_VERSION 1 /* DWARF2 */
+#define DW_DEBUG_FRAME_VERSION3 3 /* DWARF3 */
+#define DW_DEBUG_FRAME_VERSION4 4 /* DWARF4 */
+/* The following is SGI/IRIX specific, and probably no longer
+ in use anywhere. */
+#define DW_DEBUG_FRAME_AUGMENTER_STRING "mti v1"
+
+/* The value of the offset field for Cie's. */
+#define DW_CIE_OFFSET ~(0x0)
+
+/* The augmentation string may be NULL. */
+#define DW_EMPTY_STRING ""
+
+#define DW_FRAME_INSTR_OPCODE_SHIFT 6
+#define DW_FRAME_INSTR_OFFSET_MASK 0x3f
+
+/*
+ This struct denotes the rule for a register in a row of
+ the frame table. In other words, it is one element of
+ the table.
+*/
+struct Dwarf_Reg_Rule_s {
+
+ /*
+ Is a flag indicating whether the rule includes the offset
+ field, ie whether the ru_offset field is valid or not.
+ Applies only if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET.
+ It is important, since reg+offset (offset of 0) is different from
+ just 'register' since the former means 'read memory at address
+ given by the sum of register contents plus offset to get the
+ value'. whereas the latter means 'the value is in the register'.
+
+ The 'register' numbers are either real registers (ie, table
+ columns defined as real registers) or defined entries that are
+ not really hardware registers, such as DW_FRAME_SAME_VAL or
+ DW_FRAME_CFA_COL.
+
+ */
+ Dwarf_Sbyte ru_is_off;
+
+ /* DW_EXPR_OFFSET (0, DWARF2)
+ DW_EXPR_VAL_OFFSET 1 (dwarf2/3)
+ DW_EXPR_EXPRESSION 2 (dwarf2/3)
+ DW_EXPR_VAL_EXPRESSION 3 (dwarf2/3)
+ See dwarf_frame.h. */
+ Dwarf_Sbyte ru_value_type;
+
+ /* Register involved in this rule. */
+ Dwarf_Half ru_register;
+
+ /* Offset to add to register, if indicated by ru_is_offset
+ and if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET.
+ If DW_EXPR_EXPRESSION or DW_EXPR_VAL_EXPRESSION
+ this is DW_FORM_block block-length, not offset. */
+ Dwarf_Unsigned ru_offset_or_block_len;
+
+ /* For DW_EXPR_EXPRESSION DW_EXPR_VAL_EXPRESSION these is set,
+ else 0. */
+ Dwarf_Small *ru_block;
+};
+
+typedef struct Dwarf_Frame_s *Dwarf_Frame;
+
+/*
+ This structure represents a row of the frame table.
+ Fr_loc is the pc value for this row, and Fr_reg
+ contains the rule for each column.
+
+ Entry DW_FRAME_CFA_COL of fr_reg was the tradional MIPS
+ way of setting CFA. cfa_rule is the new one.
+*/
+struct Dwarf_Frame_s {
+
+ /* Pc value corresponding to this row of the frame table. */
+ Dwarf_Addr fr_loc;
+
+ /* Rules for all the registers in this row. */
+ struct Dwarf_Reg_Rule_s fr_cfa_rule;
+
+ /* fr_reg_count is the the number of
+ entries of the fr_reg array. */
+ unsigned long fr_reg_count;
+ struct Dwarf_Reg_Rule_s *fr_reg;
+
+ Dwarf_Frame fr_next;
+};
+
+typedef struct Dwarf_Frame_Op_List_s *Dwarf_Frame_Op_List;
+
+/* This is used to chain together Dwarf_Frame_Op structures. */
+struct Dwarf_Frame_Op_List_s {
+ Dwarf_Frame_Op *fl_frame_instr;
+ Dwarf_Frame_Op_List fl_next;
+};
+
+/* See dwarf_frame.c for the heuristics used to set the
+ Dwarf_Cie ci_augmentation_type.
+
+ This succinctly helps interpret the size and meaning of .debug_frame
+ and (for gcc) .eh_frame.
+
+ In the case of gcc .eh_frame (gcc 3.3, 3.4)
+ z may be followed by one or more of
+ L R P.
+
+*/
+enum Dwarf_augmentation_type {
+ aug_empty_string, /* Default empty augmentation string. */
+ aug_irix_exception_table, /* IRIX plain "z",
+ for exception handling, IRIX CC compiler.
+ Proposed z1 z2 ... never implemented. */
+ aug_gcc_eh_z, /* gcc z augmentation, (including
+ L R P variations). gcc 3.3 3.4 exception
+ handling in eh_frame. */
+ aug_irix_mti_v1, /* IRIX "mti v1" augmentation string. Probably
+ never in any released SGI-IRIX compiler. */
+ aug_eh, /* For gcc .eh_frame, "eh" is the string.,
+ gcc 1,2, egcs. Older values. */
+ aug_armcc, /* "armcc+" meaning the cfa calculation
+ is corrected to be standard (output by
+ Arm C RVCT 3.0 SP1 and later). See
+ http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
+ for details. */
+ aug_unknown, /* Unknown augmentation, we cannot do much. */
+ aug_past_last
+};
+
+
+/*
+ This structure contains all the pertinent info for a Cie. Most
+ of the fields are taken straight from the definition of a Cie.
+ Ci_cie_start points to the address (in .debug_frame) where this
+ Cie begins. Ci_cie_instr_start points to the first byte of the
+ frame instructions for this Cie. Ci_dbg points to the associated
+ Dwarf_Debug structure. Ci_initial_table is a pointer to the table
+ row generated by the instructions for this Cie.
+*/
+struct Dwarf_Cie_s {
+ Dwarf_Unsigned ci_length;
+ char *ci_augmentation;
+ Dwarf_Small ci_code_alignment_factor;
+ Dwarf_Sbyte ci_data_alignment_factor;
+ Dwarf_Small ci_return_address_register;
+ Dwarf_Small *ci_cie_start;
+ Dwarf_Small *ci_cie_instr_start;
+ Dwarf_Debug ci_dbg;
+ Dwarf_Frame ci_initial_table;
+ Dwarf_Cie ci_next;
+ Dwarf_Small ci_length_size;
+ Dwarf_Small ci_extension_size;
+ Dwarf_Half ci_cie_version_number;
+ enum Dwarf_augmentation_type ci_augmentation_type;
+
+ /* The following 2 for GNU .eh_frame exception handling
+ Augmentation Data. Set if ci_augmentation_type
+ is aug_gcc_eh_z. Zero if unused. */
+ Dwarf_Unsigned ci_gnu_eh_augmentation_len;
+ Dwarf_Ptr ci_gnu_eh_augmentation_bytes;
+
+ /* These are extracted from the gnu eh_frame
+ augmentation if the
+ augmentation begins with 'z'. See Linux LSB documents.
+ Otherwize these are zero. */
+ unsigned char ci_gnu_personality_handler_encoding;
+ unsigned char ci_gnu_lsda_encoding;
+ unsigned char ci_gnu_fde_begin_encoding;
+
+ /* If 'P' augmentation present, is handler addr. Else
+ is zero. */
+ Dwarf_Addr ci_gnu_personality_handler_addr;
+
+
+ /* In creating list of cie's (which will become an array)
+ record the position so fde can get it on fde creation. */
+ Dwarf_Unsigned ci_index;
+ Dwarf_Small * ci_section_ptr;
+ /* DWARF4 adds address size and segment size to the CIE: the .debug_info
+ section may not always be present to allow libdwarf to
+ find address_size from the compilation-unit. */
+ Dwarf_Half ci_address_size;
+ Dwarf_Half ci_segment_size;
+
+};
+
+/*
+ This structure contains all the pertinent info for a Fde.
+ Most of the fields are taken straight from the definition.
+ fd_cie_index is the index of the Cie associated with this
+ Fde in the list of Cie's for this debug_frame. Fd_cie
+ points to the corresponsing Dwarf_Cie structure. Fd_fde_start
+ points to the start address of the Fde. Fd_fde_instr_start
+ points to the start of the instructions for this Fde. Fd_dbg
+ points to the associated Dwarf_Debug structure.
+*/
+struct Dwarf_Fde_s {
+ Dwarf_Unsigned fd_length;
+ Dwarf_Addr fd_cie_offset;
+ Dwarf_Unsigned fd_cie_index;
+ Dwarf_Cie fd_cie;
+ Dwarf_Addr fd_initial_location;
+ Dwarf_Small *fd_initial_loc_pos;
+ Dwarf_Addr fd_address_range;
+ Dwarf_Small *fd_fde_start;
+ Dwarf_Small *fd_fde_instr_start;
+ Dwarf_Debug fd_dbg;
+
+ /* fd_offset_into_exception_tables is SGI/IRIX exception table
+ offset. Unused and zero if not IRIX .debug_frame. */
+ Dwarf_Signed fd_offset_into_exception_tables;
+
+ Dwarf_Fde fd_next;
+ Dwarf_Small fd_length_size;
+ Dwarf_Small fd_extension_size;
+ /* So we know from an fde which 'count' of fde-s in
+ Dwarf_Debug applies: eh or standard. */
+ Dwarf_Small fd_is_eh;
+ /* The following 2 for GNU .eh_frame exception handling
+ Augmentation Data. Set if CIE ci_augmentation_type
+ is aug_gcc_eh_z. Zero if unused. */
+ Dwarf_Unsigned fd_gnu_eh_augmentation_len;
+ Dwarf_Ptr fd_gnu_eh_augmentation_bytes;
+ Dwarf_Addr fd_gnu_eh_lsda; /* If 'L' augmentation letter
+ present: is address of the
+ Language Specific Data Area (LSDA). If not 'L" is zero. */
+
+ /* The following 3 are about the Elf section the FDEs come from. */
+ Dwarf_Small * fd_section_ptr;
+ Dwarf_Unsigned fd_section_length;
+ Dwarf_Unsigned fd_section_index;
+
+};
+
+
+int
+ _dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
+ Dwarf_Off ** offsetlist,
+ Dwarf_Signed * returncount,
+ Dwarf_Error * err);
+
+int
+_dwarf_get_fde_list_internal(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc, /* If non-zero,
+ this is gcc eh_frame. */
+ Dwarf_Error * error);
+
+enum Dwarf_augmentation_type
+_dwarf_get_augmentation_type(Dwarf_Debug dbg,
+ Dwarf_Small *augmentation_string,
+ int is_gcc_eh_frame);
+
+Dwarf_Unsigned _dwarf_get_return_address_reg(Dwarf_Small *frame_ptr,
+ int version,
+ unsigned long *size);
+
+/* Temporary recording of crucial cie/fde prefix data.
+ * Vastly simplifies some argument lists.
+ */
+struct cie_fde_prefix_s {
+ /* cf_start_addr is a pointer to the first byte of this fde/cie
+ we are reading now. */
+ Dwarf_Small * cf_start_addr;
+ Dwarf_Small * cf_addr_after_prefix;
+ Dwarf_Unsigned cf_length;
+ int cf_local_length_size;
+ int cf_local_extension_size;
+ Dwarf_Unsigned cf_cie_id;
+ Dwarf_Small * cf_cie_id_addr; /* used for eh_frame calculations. */
+
+ /* Simplifies passing around these values to create fde having
+ these here. */
+ /* cf_section_ptr is a pointer to the first byte
+ of the object section the prefix is read from. */
+ Dwarf_Small * cf_section_ptr;
+ Dwarf_Unsigned cf_section_index;
+ Dwarf_Unsigned cf_section_length;
+};
+
+int
+_dwarf_exec_frame_instr(Dwarf_Bool make_instr,
+ Dwarf_Frame_Op ** ret_frame_instr,
+ Dwarf_Bool search_pc,
+ Dwarf_Addr search_pc_val,
+ Dwarf_Addr initial_loc,
+ Dwarf_Small * start_instr_ptr,
+ Dwarf_Small * final_instr_ptr,
+ Dwarf_Frame table,
+ Dwarf_Cie cie,
+ Dwarf_Debug dbg,
+ Dwarf_Half reg_num_of_cfa,
+ Dwarf_Sword * returned_count,
+ int *returned_error);
+
+
+int dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
+ Dwarf_Small *frame_ptr_in,
+ Dwarf_Small *section_ptr_in,
+ Dwarf_Unsigned section_index_in,
+ Dwarf_Unsigned section_length_in,
+ struct cie_fde_prefix_s *prefix_out,
+ Dwarf_Error *error);
+
+int dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s * prefix,
+ Dwarf_Small *section_pointer,
+ Dwarf_Small *frame_ptr,
+ int use_gnu_cie_calc,
+ Dwarf_Cie cie_ptr_in,
+ Dwarf_Fde *fde_ptr_out,
+ Dwarf_Error *error);
+
+int dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small* section_pointer,
+ Dwarf_Small* frame_ptr,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie *cie_ptr_out,
+ Dwarf_Error *error);
+
+
+int _dwarf_frame_constructor(Dwarf_Debug dbg,void * );
+void _dwarf_frame_destructor (void *);
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame2.c b/usr/src/lib/libdwarf/common/dwarf_frame2.c
new file mode 100644
index 0000000000..01b9ec497b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame2.c
@@ -0,0 +1,1540 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+/*
+ This implements _dwarf_get_fde_list_internal()
+ and related helper functions for reading cie/fde data.
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* using Arange as a way to build a
+ list */
+
+
+static int dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr);
+static void dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
+ Dwarf_Cie head_cie_ptr);
+static int dwarf_create_cie_from_start(Dwarf_Debug dbg,
+ Dwarf_Small * cie_ptr_val,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Small * frame_ptr_end,
+ Dwarf_Unsigned cie_id_value,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Error * error);
+
+static Dwarf_Small *get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * cie_id_addr);
+static int get_gcc_eh_augmentation(Dwarf_Debug dbg,
+ Dwarf_Small * frame_ptr,
+ unsigned long
+ *size_of_augmentation_data,
+ enum Dwarf_augmentation_type augtype,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * fde_eh_encoding_out,
+ char *augmentation);
+
+static int
+ gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
+ Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
+ Dwarf_Half address_size,
+ unsigned char *pers_hand_enc_out,
+ unsigned char *lsda_enc_out,
+ unsigned char *fde_begin_enc_out,
+ Dwarf_Addr * gnu_pers_addr_out);
+
+
+static int read_encoded_ptr(Dwarf_Debug dbg,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * input_field,
+ int gnu_encoding,
+ Dwarf_Half address_size,
+ Dwarf_Unsigned * addr,
+ Dwarf_Small ** input_field_out);
+
+
+
+static int qsort_compare(const void *elem1, const void *elem2);
+
+
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
+static void
+chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur)
+{
+ if (*head == NULL)
+ *head = newone;
+ else {
+ (*cur)->fd_next = newone;
+ }
+ *cur = newone;
+
+}
+
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
+static void
+chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur)
+{
+ if (*head == NULL) {
+ *head = newone;
+ } else {
+ (*cur)->ci_next = newone;
+ }
+ *cur = newone;
+}
+
+/* The size of the length field plus the
+ value of length must be an integral
+ multiple of the address size. Dwarf4 standard.
+
+ A constant that gives the number of bytes of the CIE
+ structure, not including the length field itself
+ (where length mod <size of an address> == 0)
+ (see Section 7.2.2). Dwarf3 standard.
+
+ A uword constant that gives the number of bytes of
+ the CIE structure, not including the
+ length field, itself (length mod <addressing unit size> == 0).
+ Dwarf2 standard.*/
+static void
+validate_length(Dwarf_Debug dbg,
+ Dwarf_Cie cieptr, Dwarf_Unsigned length,
+ Dwarf_Unsigned length_size,
+ Dwarf_Unsigned extension_size,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * ciefde_start,
+ const char * cieorfde)
+{
+ Dwarf_Unsigned address_size = cieptr->ci_address_size;
+ Dwarf_Unsigned length_field_summed = length_size + extension_size;
+ Dwarf_Unsigned total_len = length + length_field_summed;
+ Dwarf_Unsigned mod = total_len % address_size;
+
+ if (mod != 0) {
+ char msg[DW_HARMLESS_ERROR_MSG_STRING_SIZE];
+ Dwarf_Unsigned sectionoffset = ciefde_start - section_ptr;
+ snprintf(msg,sizeof(msg),
+ "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE"
+ " len=0x%" DW_PR_DUx
+ ", len size=0x%" DW_PR_DUx
+ ", extn size=0x%" DW_PR_DUx
+ ", totl length=0x%" DW_PR_DUx
+ ", addr size=0x%" DW_PR_DUx
+ ", mod=0x%" DW_PR_DUx " must be zero"
+ " in %s"
+ ", offset 0x%" DW_PR_DUx ".",
+ length,
+ length_size,
+ extension_size,
+ total_len,address_size, mod,
+ cieorfde,
+ sectionoffset);
+ dwarf_insert_harmless_error(dbg,msg);
+ }
+ return;
+}
+
+
+#if 0
+/* For debugging only. */
+static void
+print_prefix(struct cie_fde_prefix_s *prefix, int line)
+{
+ printf("prefix-print, prefix at 0x%lx, line %d\n",
+ (long) prefix, line);
+ printf(" start addr 0x%lx after prefix 0x%lx\n",
+ (long) prefix->cf_start_addr,
+ (long) prefix->cf_addr_after_prefix);
+ printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n",
+ (Dwarf_Unsigned) prefix->cf_length,
+ prefix->cf_local_length_size,
+ prefix->cf_local_extension_size);
+ printf(" cie_id 0x%" DW_PR_DUx " cie_id cie_id_addr 0x%lx\n",
+ (Dwarf_Unsigned) prefix->cf_cie_id,
+ (long) prefix->cf_cie_id_addr);
+ printf
+ (" sec ptr 0x%lx sec index %" DW_PR_DSd " sec len 0x%" DW_PR_DUx " sec past end 0x%lx\n",
+ (long) prefix->cf_section_ptr,
+ (Dwarf_Signed) prefix->cf_section_index,
+ (Dwarf_Unsigned) prefix->cf_section_length,
+ (long) prefix->cf_section_ptr + prefix->cf_section_length);
+}
+#endif
+
+
+
+/* Internal function called from various places to create
+ lists of CIEs and FDEs. Not directly called
+ by consumer code */
+int
+_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc, Dwarf_Error * error)
+{
+ /* Scans the debug_frame section. */
+ Dwarf_Small *frame_ptr = section_ptr;
+ Dwarf_Small *frame_ptr_end = section_ptr + section_length;
+
+
+
+ /*
+ New_cie points to the Cie being read, and head_cie_ptr and
+ cur_cie_ptr are used for chaining them up in sequence.
+ In case cie's are reused aggressively we need tail_cie_ptr
+ to add to the chain. If we re-use an early cie
+ later on, that does not mean we chain a new cie to the early one,
+ we always chain it to the tail. */
+ Dwarf_Cie head_cie_ptr = NULL;
+ Dwarf_Cie cur_cie_ptr = NULL;
+ Dwarf_Cie tail_cie_ptr = NULL;
+ Dwarf_Word cie_count = 0;
+
+ /*
+ Points to a list of contiguous pointers to Dwarf_Cie structures.
+ */
+ Dwarf_Cie *cie_list_ptr = 0;
+
+
+ /*
+ New_fde points to the Fde being created, and head_fde_ptr and
+ cur_fde_ptr are used to chain them up. */
+ Dwarf_Fde head_fde_ptr = NULL;
+ Dwarf_Fde cur_fde_ptr = NULL;
+ Dwarf_Word fde_count = 0;
+
+ /*
+ Points to a list of contiguous pointers to Dwarf_Fde structures.
+ */
+ Dwarf_Fde *fde_list_ptr = NULL;
+
+ Dwarf_Word i = 0;
+ int res = DW_DLV_ERROR;
+
+ if (frame_ptr == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ /* We create the fde and cie arrays. Processing each CIE as we come
+ to it or as an FDE refers to it. We cannot process 'late' CIEs
+ late as GNU .eh_frame complexities mean we need the whole CIE
+ before we can process the FDE correctly. */
+ while (frame_ptr < frame_ptr_end) {
+
+ struct cie_fde_prefix_s prefix;
+
+ /* First read in the 'common prefix' to figure out what we are
+ to do with this entry. */
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg,
+ frame_ptr, section_ptr,
+ section_index,
+ section_length, &prefix, error);
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ break;
+ frame_ptr = prefix.cf_addr_after_prefix;
+ if (frame_ptr >= frame_ptr_end) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+
+ }
+
+ if (prefix.cf_cie_id == cie_id_value) {
+ /* This is a CIE. */
+ Dwarf_Cie cie_ptr_to_use = 0;
+
+ int res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+
+ if (res == DW_DLV_OK) {
+ cur_cie_ptr = cie_ptr_to_use;
+ /* Ok. Seen already. */
+ } else if (res == DW_DLV_NO_ENTRY) {
+ /* CIE before its FDE in this case. */
+ res = dwarf_create_cie_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ /* ASSERT: res==DW_DLV_NO_ENTRY impossible. */
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ }
+ /* ASSERT res != DW_DLV_NO_ENTRY */
+ cie_count++;
+ chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
+ &tail_cie_ptr);
+ cur_cie_ptr = tail_cie_ptr;
+ } else { /* res == DW_DLV_ERROR */
+
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ }
+ frame_ptr = cie_ptr_to_use->ci_cie_start +
+ cie_ptr_to_use->ci_length +
+ cie_ptr_to_use->ci_length_size +
+ cie_ptr_to_use->ci_extension_size;
+ continue;
+ } else {
+ /* this is an FDE, Frame Description Entry, see the Dwarf
+ Spec, section 6.4.1 */
+ int res = DW_DLV_ERROR;
+ Dwarf_Cie cie_ptr_to_use = 0;
+ Dwarf_Fde fde_ptr_to_use = 0;
+
+ /* Do not call this twice on one prefix, as
+ prefix.cf_cie_id_addr is altered as a side effect. */
+ Dwarf_Small *cieptr_val =
+ get_cieptr_given_offset(prefix.cf_cie_id,
+ use_gnu_cie_calc,
+ section_ptr,
+ prefix.cf_cie_id_addr);
+
+ res = dwarf_find_existing_cie_ptr(cieptr_val,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+ if (res == DW_DLV_OK) {
+ cur_cie_ptr = cie_ptr_to_use;
+ /* Ok. Seen CIE already. */
+ } else if (res == DW_DLV_NO_ENTRY) {
+ res = dwarf_create_cie_from_start(dbg,
+ cieptr_val,
+ section_ptr,
+ section_index,
+ section_length,
+ frame_ptr_end,
+ cie_id_value,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ ++cie_count;
+ chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
+ &tail_cie_ptr);
+ cur_cie_ptr = tail_cie_ptr;
+
+ } else {
+ /* DW_DLV_ERROR */
+ return res;
+ }
+
+ res = dwarf_create_fde_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ use_gnu_cie_calc,
+ cie_ptr_to_use,
+ &fde_ptr_to_use,
+ error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr);
+ fde_count++;
+ /* ASSERT: DW_DLV_OK. */
+ frame_ptr = fde_ptr_to_use->fd_fde_start +
+ fde_ptr_to_use->fd_length +
+ fde_ptr_to_use->fd_length_size +
+ fde_ptr_to_use->fd_extension_size;
+ continue;
+
+ }
+
+ }
+
+ /* Now build list of CIEs from the list. If there are no CIEs
+ there should be no FDEs. */
+ if (cie_count > 0) {
+ cie_list_ptr = (Dwarf_Cie *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count);
+ } else {
+ if(fde_count > 0) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_ORPHAN_FDE);
+ return DW_DLV_ERROR;
+ }
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ return DW_DLV_NO_ENTRY;
+ }
+ if (cie_list_ptr == NULL) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return DW_DLV_ERROR;
+ }
+ cur_cie_ptr = head_cie_ptr;
+ for (i = 0; i < cie_count; i++) {
+ *(cie_list_ptr + i) = cur_cie_ptr;
+ cur_cie_ptr = cur_cie_ptr->ci_next;
+ }
+
+
+
+ /* Now build array of FDEs from the list.
+ With orphan CIEs (meaning no FDEs) lets not return DW_DLV_NO_ENTRY */
+ if (fde_count > 0) {
+ fde_list_ptr = (Dwarf_Fde *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count);
+ }
+
+ /* It is ok if fde_list_ptr is NULL, we just have no fdes. */
+ cur_fde_ptr = head_fde_ptr;
+ for (i = 0; i < fde_count; i++) {
+ *(fde_list_ptr + i) = cur_fde_ptr;
+ cur_fde_ptr = cur_fde_ptr->fd_next;
+ }
+
+
+ /* Return arguments. */
+ *cie_data = cie_list_ptr;
+ *cie_element_count = cie_count;
+
+ *fde_data = fde_list_ptr;
+ *fde_element_count = fde_count;
+ if(use_gnu_cie_calc) {
+ dbg->de_fde_data_eh = fde_list_ptr;
+ dbg->de_fde_count_eh = fde_count;
+ dbg->de_cie_data_eh = cie_list_ptr;
+ dbg->de_cie_count_eh = cie_count;
+ } else {
+ dbg->de_fde_data = fde_list_ptr;
+ dbg->de_fde_count = fde_count;
+ dbg->de_cie_data = cie_list_ptr;
+ dbg->de_cie_count = cie_count;
+ }
+
+ /* Sort the list by the address so that dwarf_get_fde_at_pc() can
+ binary search this list. */
+ if(fde_count > 0) {
+ qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr),
+ qsort_compare);
+ }
+
+ return (DW_DLV_OK);
+}
+
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Cie_s structure.
+*/
+int
+dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * frame_ptr,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Cie new_cie = 0;
+
+ /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses
+ -1 (in .debug_frame). .eh_frame not quite identical to
+ .debug_frame */
+ /* We here default the address size as it is not present
+ in DWARF2 or DWARF3 cie data, below we set it right if
+ it is present. */
+ Dwarf_Half address_size = dbg->de_pointer_size;
+ Dwarf_Small eh_fde_encoding = 0;
+ Dwarf_Small *augmentation = 0;
+ Dwarf_Half segment_size = 0;
+ Dwarf_Sword data_alignment_factor = -1;
+ Dwarf_Word code_alignment_factor = 4;
+ Dwarf_Unsigned return_address_register = 31;
+ int local_length_size = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned cie_aug_data_len = 0;
+ Dwarf_Small *cie_aug_data = 0;
+ Dwarf_Addr gnu_personality_handler_addr = 0;
+ unsigned char gnu_personality_handler_encoding = 0;
+ unsigned char gnu_lsda_encoding = 0;
+ unsigned char gnu_fde_begin_encoding = 0;
+
+
+ enum Dwarf_augmentation_type augt = aug_unknown;
+
+
+ /* this is a CIE, Common Information Entry: See the dwarf spec,
+ section 6.4.1 */
+ Dwarf_Small version = *(Dwarf_Small *) frame_ptr;
+
+ frame_ptr++;
+ if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 &&
+ version != DW_CIE_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ augmentation = frame_ptr;
+ frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1;
+ augt = _dwarf_get_augmentation_type(dbg,
+ augmentation, use_gnu_cie_calc);
+ if (augt == aug_eh) {
+ /* REFERENCED *//* Not used in this instance */
+ Dwarf_Unsigned exception_table_addr;
+
+ /* this is per egcs-1.1.2 as on RH 6.0 */
+ READ_UNALIGNED(dbg, exception_table_addr,
+ Dwarf_Unsigned, frame_ptr, local_length_size);
+ frame_ptr += local_length_size;
+ }
+ {
+ Dwarf_Unsigned lreg = 0;
+ unsigned long size = 0;
+
+ if( version == DW_CIE_VERSION4) {
+ address_size = *((unsigned char *)frame_ptr);
+ ++frame_ptr;
+ segment_size = *((unsigned char *)frame_ptr);
+ ++frame_ptr;
+ }
+
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ code_alignment_factor = (Dwarf_Word) lreg;
+
+ data_alignment_factor =
+ (Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr,
+ &leb128_length);
+
+ frame_ptr = frame_ptr + leb128_length;
+
+ return_address_register =
+ _dwarf_get_return_address_reg(frame_ptr, version, &size);
+ if (return_address_register > dbg->de_frame_reg_rules_entry_count) {
+ _dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR);
+ return (DW_DLV_ERROR);
+ }
+ frame_ptr += size;
+ }
+ switch (augt) {
+ case aug_empty_string:
+ break;
+ case aug_irix_mti_v1:
+ break;
+ case aug_irix_exception_table:{
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Word length_of_augmented_fields;
+
+ /* Decode the length of augmented fields. */
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ length_of_augmented_fields = (Dwarf_Word) lreg;
+
+
+ /* set the frame_ptr to point at the instruction start. */
+ frame_ptr += length_of_augmented_fields;
+ }
+ break;
+
+ case aug_eh:{
+
+ int err = 0;
+ unsigned long increment = 0;
+
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+
+ err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
+ augt,
+ prefix->cf_section_ptr,
+ &eh_fde_encoding,
+ (char *) augmentation);
+ if (err == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr += increment;
+ break;
+ }
+ case aug_gcc_eh_z:{
+ /* Here we have Augmentation Data Length (uleb128) followed
+ by Augmentation Data bytes. */
+ int res = DW_DLV_ERROR;
+ Dwarf_Unsigned adlen = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, adlen);
+ cie_aug_data_len = adlen;
+ cie_aug_data = frame_ptr;
+ res = gnu_aug_encodings(dbg,
+ (char *) augmentation,
+ cie_aug_data,
+ cie_aug_data_len,
+ address_size,
+ &gnu_personality_handler_encoding,
+ &gnu_lsda_encoding,
+ &gnu_fde_begin_encoding,
+ &gnu_personality_handler_addr);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return res;
+ }
+
+
+ frame_ptr += adlen;
+ break;
+ }
+ case aug_armcc:
+ break;
+ default:{
+ /* We do not understand the augmentation string. No
+ assumption can be made about any fields other than what
+ we have already read. */
+ frame_ptr = prefix->cf_start_addr +
+ prefix->cf_length + prefix->cf_local_length_size
+ + prefix->cf_local_extension_size;
+ /* FIX -- What are the values of data_alignment_factor,
+ code_alignement_factor, return_address_register and
+ instruction start? They were clearly uninitalized in the
+ previous version and I am leaving them the same way. */
+ break;
+ }
+ } /* End switch on augmentation type. */
+
+ new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1);
+ if (new_cie == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_cie->ci_cie_version_number = version;
+ new_cie->ci_initial_table = NULL;
+ new_cie->ci_length = (Dwarf_Word) prefix->cf_length;
+ new_cie->ci_length_size = prefix->cf_local_length_size;
+ new_cie->ci_extension_size = prefix->cf_local_extension_size;
+ new_cie->ci_augmentation = (char *) augmentation;
+
+ new_cie->ci_data_alignment_factor =
+ (Dwarf_Sbyte) data_alignment_factor;
+ new_cie->ci_code_alignment_factor =
+ (Dwarf_Small) code_alignment_factor;
+ new_cie->ci_return_address_register = return_address_register;
+ new_cie->ci_cie_start = prefix->cf_start_addr;
+ new_cie->ci_cie_instr_start = frame_ptr;
+ new_cie->ci_dbg = dbg;
+ new_cie->ci_augmentation_type = augt;
+ new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len;
+ new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data;
+ new_cie->ci_gnu_personality_handler_encoding =
+ gnu_personality_handler_encoding;
+ new_cie->ci_gnu_personality_handler_addr =
+ gnu_personality_handler_addr;
+ new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding;
+ new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding;
+
+ new_cie->ci_index = cie_count;
+ new_cie->ci_section_ptr = prefix->cf_section_ptr;
+ /* The Following new in DWARF4 */
+ new_cie->ci_address_size = address_size;
+ new_cie->ci_segment_size = segment_size;
+ validate_length(dbg,new_cie,new_cie->ci_length,
+ new_cie->ci_length_size, new_cie->ci_extension_size,
+ new_cie->ci_section_ptr,
+ new_cie->ci_cie_start,"cie");
+
+ *cie_ptr_out = new_cie;
+ return DW_DLV_OK;
+
+}
+
+
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Fde_s structure.
+*/
+
+int
+dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * frame_ptr,
+ int use_gnu_cie_calc,
+ Dwarf_Cie cie_ptr_in,
+ Dwarf_Fde * fde_ptr_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Fde new_fde = 0;
+ Dwarf_Cie cieptr = cie_ptr_in;
+ Dwarf_Small *saved_frame_ptr = 0;
+
+ Dwarf_Small *initloc = frame_ptr;
+ Dwarf_Signed offset_into_exception_tables
+ /* must be min dwarf_sfixed in size */
+ = (Dwarf_Signed) DW_DLX_NO_EH_OFFSET;
+ Dwarf_Small *fde_aug_data = 0;
+ Dwarf_Unsigned fde_aug_data_len = 0;
+ Dwarf_Addr cie_base_offset = prefix->cf_cie_id;
+ Dwarf_Addr initial_location = 0; /* must be min de_pointer_size
+ bytes in size */
+ Dwarf_Addr address_range = 0; /* must be min de_pointer_size
+ bytes in size */
+ Dwarf_Half address_size = cie_ptr_in->ci_address_size;
+
+ enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type;
+
+ if (augt == aug_gcc_eh_z) {
+ /* If z augmentation this is eh_frame, and initial_location and
+ address_range in the FDE are read according to the CIE
+ augmentation string instructions. */
+
+ {
+ Dwarf_Small *fp_updated = 0;
+ int res = read_encoded_ptr(dbg,
+ section_pointer,
+ frame_ptr,
+ cieptr-> ci_gnu_fde_begin_encoding,
+ address_size,
+ &initial_location,
+ &fp_updated);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = fp_updated;
+ /* For the address-range it makes no sense to be
+ pc-relative, so we turn it off with a section_pointer of
+ NULL. Masking off DW_EH_PE_pcrel from the
+ ci_gnu_fde_begin_encoding in this call would also work
+ to turn off DW_EH_PE_pcrel. */
+ res = read_encoded_ptr(dbg, (Dwarf_Small *) NULL,
+ frame_ptr,
+ cieptr->ci_gnu_fde_begin_encoding,
+ address_size,
+ &address_range, &fp_updated);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = fp_updated;
+ }
+ {
+ Dwarf_Unsigned adlen = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, adlen);
+ fde_aug_data_len = adlen;
+ fde_aug_data = frame_ptr;
+ frame_ptr += adlen;
+ }
+
+ } else {
+ READ_UNALIGNED(dbg, initial_location, Dwarf_Addr,
+ frame_ptr, address_size);
+ frame_ptr += address_size;
+
+ READ_UNALIGNED(dbg, address_range, Dwarf_Addr,
+ frame_ptr, address_size);
+ frame_ptr += address_size;
+ }
+
+
+
+
+
+ switch (augt) {
+ case aug_irix_mti_v1:
+ case aug_empty_string:
+ break;
+ case aug_irix_exception_table:{
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Word length_of_augmented_fields = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ length_of_augmented_fields = (Dwarf_Word) lreg;
+
+ saved_frame_ptr = frame_ptr;
+ /* The first word is an offset into exception tables.
+ Defined as a 32bit offset even for CC -64. */
+ READ_UNALIGNED(dbg, offset_into_exception_tables,
+ Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed));
+ SIGN_EXTEND(offset_into_exception_tables,
+ sizeof(Dwarf_sfixed));
+ frame_ptr = saved_frame_ptr + length_of_augmented_fields;
+ }
+ break;
+ case aug_eh:{
+ Dwarf_Unsigned eh_table_value = 0;
+
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+
+ /* gnu eh fde case. we do not need to do anything */
+ /*REFERENCED*/ /* Not used in this instance of the
+ macro */
+ READ_UNALIGNED(dbg, eh_table_value,
+ Dwarf_Unsigned, frame_ptr,
+ address_size);
+ frame_ptr += address_size;
+ }
+ break;
+
+ case aug_gcc_eh_z:{
+ /* The Augmentation Data Length is here, followed by the
+ Augmentation Data bytes themselves. */
+ }
+ break;
+ case aug_armcc:
+ break;
+ case aug_past_last:
+ break;
+ case aug_unknown:
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ } /* End switch on augmentation type */
+ new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1);
+ if (new_fde == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_fde->fd_length = prefix->cf_length;
+ new_fde->fd_length_size = prefix->cf_local_length_size;
+ new_fde->fd_extension_size = prefix->cf_local_extension_size;
+ new_fde->fd_is_eh = use_gnu_cie_calc;
+ new_fde->fd_cie_offset = cie_base_offset;
+ new_fde->fd_cie_index = cieptr->ci_index;
+ new_fde->fd_cie = cieptr;
+ new_fde->fd_initial_location = initial_location;
+ new_fde->fd_initial_loc_pos = initloc;
+ new_fde->fd_address_range = address_range;
+ new_fde->fd_fde_start = prefix->cf_start_addr;
+ new_fde->fd_fde_instr_start = frame_ptr;
+ new_fde->fd_dbg = dbg;
+ new_fde->fd_offset_into_exception_tables =
+ offset_into_exception_tables;
+
+ new_fde->fd_section_ptr = prefix->cf_section_ptr;
+ new_fde->fd_section_index = prefix->cf_section_index;
+ new_fde->fd_section_length = prefix->cf_section_length;
+
+ new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data;
+ new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len;
+ validate_length(dbg,cieptr,new_fde->fd_length,
+ new_fde->fd_length_size, new_fde->fd_extension_size,
+ new_fde->fd_section_ptr,new_fde->fd_fde_start,"fde");
+
+
+ *fde_ptr_out = new_fde;
+ return DW_DLV_OK;
+}
+
+/* called by qsort to compare FDE entries.
+ Consumer code expects the array of FDE pointers to be in address order.
+*/
+static int
+qsort_compare(const void *elem1, const void *elem2)
+{
+ Dwarf_Fde fde1 = *(Dwarf_Fde *) elem1;
+ Dwarf_Fde fde2 = *(Dwarf_Fde *) elem2;
+ Dwarf_Addr addr1 = fde1->fd_initial_location;
+ Dwarf_Addr addr2 = fde2->fd_initial_location;
+
+ if (addr1 < addr2) {
+ return -1;
+ } else if (addr1 > addr2) {
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Read in the common cie/fde prefix, including reading
+ * the cie-value which shows which this is: cie or fde.
+ * */
+int
+dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * frame_ptr_in,
+ Dwarf_Small * section_ptr_in,
+ Dwarf_Unsigned section_index_in,
+ Dwarf_Unsigned section_length_in,
+ struct cie_fde_prefix_s *data_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned length = 0;
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Small *frame_ptr = frame_ptr_in;
+ Dwarf_Small *cie_ptr_addr = 0;
+ Dwarf_Unsigned cie_id = 0;
+
+ /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ frame_ptr, local_length_size,
+ local_extension_size);
+
+ if (length == 0) {
+ /* nul bytes at end of section, seen at end of egcs eh_frame
+ sections (in a.out). Take this as meaning no more CIE/FDE
+ data. We should be very close to end of section. */
+ return DW_DLV_NO_ENTRY;
+ }
+
+ cie_ptr_addr = frame_ptr;
+ READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned,
+ frame_ptr, local_length_size);
+ SIGN_EXTEND(cie_id, local_length_size);
+ frame_ptr += local_length_size;
+
+ data_out->cf_start_addr = frame_ptr_in;
+ data_out->cf_addr_after_prefix = frame_ptr;
+
+ data_out->cf_length = length;
+ data_out->cf_local_length_size = local_length_size;
+ data_out->cf_local_extension_size = local_extension_size;
+ data_out->cf_cie_id = cie_id;
+ data_out->cf_cie_id_addr = cie_ptr_addr;
+ data_out->cf_section_ptr = section_ptr_in;
+ data_out->cf_section_index = section_index_in;
+ data_out->cf_section_length = section_length_in;
+ return DW_DLV_OK;
+}
+
+/* On various errors previously-allocated CIEs and FDEs
+ must be cleaned up.
+ This helps avoid leaks in case of errors.
+*/
+static void
+dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
+ Dwarf_Cie head_cie_ptr)
+{
+ Dwarf_Fde curfde = 0;
+ Dwarf_Cie curcie = 0;
+ Dwarf_Fde nextfde = 0;
+ Dwarf_Cie nextcie = 0;
+
+ for (curfde = head_fde_ptr; curfde; curfde = nextfde) {
+ nextfde = curfde->fd_next;
+ dwarf_dealloc(curfde->fd_dbg, curfde, DW_DLA_FDE);
+ }
+ for (curcie = head_cie_ptr; curcie; curcie = nextcie) {
+ Dwarf_Frame frame = curcie->ci_initial_table;
+
+ nextcie = curcie->ci_next;
+ if (frame)
+ dwarf_dealloc(curcie->ci_dbg, frame, DW_DLA_FRAME);
+ dwarf_dealloc(curcie->ci_dbg, curcie, DW_DLA_CIE);
+ }
+}
+
+/* Find the cie whose id value is given: the id
+ * value is, per DWARF2/3, an offset in the section.
+ * For .debug_frame, zero is a legal offset. For
+ * GNU .eh_frame it is not a legal offset.
+ * 'cie_ptr' is a pointer into our section, not an offset. */
+static int
+dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr)
+{
+ Dwarf_Cie next = 0;
+
+ if (cur_cie_ptr && cie_ptr == cur_cie_ptr->ci_cie_start) {
+ /* Usually, we use the same cie again and again. */
+ *cie_ptr_to_use_out = cur_cie_ptr;
+ return DW_DLV_OK;
+ }
+ for (next = head_cie_ptr; next; next = next->ci_next) {
+ if (cie_ptr == next->ci_cie_start) {
+ *cie_ptr_to_use_out = next;
+ return DW_DLV_OK;
+ }
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+/* We have a valid cie_ptr_val that has not been
+ * turned into an internal Cie yet. Do so now.
+ * Returns DW_DLV_OK or DW_DLV_ERROR, never
+ * DW_DLV_NO_ENTRY.
+
+ 'section_ptr' - Points to first byte of section data.
+ 'section_length' - Length of the section, in bytes.
+ 'frame_ptr_end' - Points 1-past last byte of section data.
+ * */
+static int
+dwarf_create_cie_from_start(Dwarf_Debug dbg,
+ Dwarf_Small * cie_ptr_val,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Small * frame_ptr_end,
+ Dwarf_Unsigned cie_id_value,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Error * error)
+{
+ struct cie_fde_prefix_s prefix;
+ int res = DW_DLV_ERROR;
+ Dwarf_Small *frame_ptr = cie_ptr_val;
+
+ if (frame_ptr < section_ptr || frame_ptr > frame_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ /* First read in the 'common prefix' to figure out what * we are to
+ do with this entry. If it is not a cie * we are in big trouble. */
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr,
+ section_index, section_length,
+ &prefix, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY) {
+ /* error. */
+ _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
+ return DW_DLV_ERROR;
+
+ }
+
+ if (prefix.cf_cie_id != cie_id_value) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = prefix.cf_addr_after_prefix;
+ res = dwarf_create_cie_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ cie_count,
+ use_gnu_cie_calc,
+ cie_ptr_to_use_out, error);
+ return res;
+
+}
+
+
+/* This is for gnu eh frames, the 'z' case.
+ We find the letter involved
+ Return the augmentation character and, if applicable,
+ the personality routine address.
+
+ personality_routine_out -
+ if 'P' is augchar, is personality handler addr.
+ Otherwise is not set.
+ aug_data - if 'P' points to data space of the
+ aug_data_len - length of areas aug_data points to.
+
+*/
+#if 0
+/* For debugging only. */
+void
+dump_bytes(Dwarf_Small * start, long len)
+{
+ Dwarf_Small *end = start + len;
+ Dwarf_Small *cur = start;
+
+ for (; cur < end; cur++) {
+ printf(" byte %d, data %02x\n", (int) (cur - start), *cur);
+ }
+
+}
+#endif
+static int
+gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
+ Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
+ Dwarf_Half address_size,
+ unsigned char *pers_hand_enc_out,
+ unsigned char *lsda_enc_out,
+ unsigned char *fde_begin_enc_out,
+ Dwarf_Addr * gnu_pers_addr_out)
+{
+ char *nc = 0;
+ Dwarf_Small *cur_aug_p = aug_data;
+ Dwarf_Small *end_aug_p = aug_data + aug_data_len;
+
+ for (nc = augmentation; *nc; ++nc) {
+ char c = *nc;
+
+ switch (c) {
+ case 'z':
+ /* Means that the augmentation data is present. */
+ continue;
+
+ case 'S':
+ /* Indicates this is a signal stack frame. Debuggers have to do
+ special handling. We don't need to do more than print this flag at
+ the right time, though (see dwarfdump where it prints the augmentation
+ string).
+ A signal stack frame (in some OS's) can only be
+ unwound (backtraced) by knowing it is a signal stack frame
+ (perhaps by noticing the name of the function for the stack frame
+ if the name can be found somehow) and figuring
+ out (or knowing) how the kernel and libc pushed a structure
+ onto the stack and loading registers from that structure.
+ Totally different from normal stack unwinding.
+ This flag gives an unwinder a big leg up by decoupling the
+ 'hint: this is a stack frame' from knowledge like
+ the function name (the name might be unavailable at unwind time).
+ */
+ break;
+
+ case 'L':
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ *lsda_enc_out = *(unsigned char *) cur_aug_p;
+ ++cur_aug_p;
+ break;
+ case 'R':
+ /* Followed by a one byte argument giving the
+ pointer encoding for the address pointers in the fde. */
+ if (cur_aug_p >= end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ *fde_begin_enc_out = *(unsigned char *) cur_aug_p;
+ ++cur_aug_p;
+ break;
+ case 'P':{
+ int res = DW_DLV_ERROR;
+ Dwarf_Small *updated_aug_p = 0;
+ unsigned char encoding = 0;
+
+ if (cur_aug_p >= end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ encoding = *(unsigned char *) cur_aug_p;
+ *pers_hand_enc_out = encoding;
+ ++cur_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ /* DW_EH_PE_pcrel makes no sense here, so we turn it
+ off via a section pointer of NULL. */
+ res = read_encoded_ptr(dbg,
+ (Dwarf_Small *) NULL,
+ cur_aug_p,
+ encoding,
+ address_size,
+ gnu_pers_addr_out,
+ &updated_aug_p);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ cur_aug_p = updated_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ }
+ break;
+ default:
+ return DW_DLV_ERROR;
+
+ }
+ }
+
+ return DW_DLV_OK;
+}
+
+/* Given augmentation character (the encoding) giving the
+address format, read the address from input_field
+and return an incremented value 1 past the input bytes of the
+address.
+Push the address read back thru the *addr pointer.
+See LSB (Linux Standar Base) exception handling documents.
+*/
+static int
+read_encoded_ptr(Dwarf_Debug dbg,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * input_field,
+ int gnu_encoding,
+ Dwarf_Half address_size,
+ Dwarf_Unsigned * addr,
+ Dwarf_Small ** input_field_updated)
+{
+ Dwarf_Word length = 0;
+ int value_type = gnu_encoding & 0xf;
+ Dwarf_Small *input_field_original = input_field;
+
+ if (gnu_encoding == 0xff) {
+ /* There is no data here. */
+
+ *addr = 0;
+ *input_field_updated = input_field;
+ /* Should we return DW_DLV_NO_ENTRY? */
+ return DW_DLV_OK;
+ }
+ switch (value_type) {
+ case DW_EH_PE_absptr:{
+ /* value_type is zero. Treat as pointer size of the object.
+ */
+ Dwarf_Unsigned ret_value = 0;
+
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, address_size);
+ *addr = ret_value;
+ *input_field_updated = input_field + address_size;
+ }
+ break;
+ case DW_EH_PE_uleb128:{
+ Dwarf_Unsigned val = _dwarf_decode_u_leb128(input_field,
+ &length);
+
+ *addr = val;
+ *input_field_updated = input_field + length;
+ }
+ break;
+ case DW_EH_PE_udata2:{
+ Dwarf_Unsigned ret_value = 0;
+
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, 2);
+ *addr = ret_value;
+ *input_field_updated = input_field + 2;
+ }
+ break;
+
+ case DW_EH_PE_udata4:{
+
+ Dwarf_Unsigned ret_value = 0;
+
+ /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, sizeof(Dwarf_ufixed));
+ *addr = ret_value;
+ *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ }
+ break;
+
+ case DW_EH_PE_udata8:{
+ Dwarf_Unsigned ret_value = 0;
+
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, sizeof(Dwarf_Unsigned));
+ *addr = ret_value;
+ *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ }
+ break;
+
+ case DW_EH_PE_sleb128:{
+ Dwarf_Signed val = _dwarf_decode_s_leb128(input_field,
+ &length);
+
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + length;
+ }
+ break;
+ case DW_EH_PE_sdata2:{
+ Dwarf_Unsigned val = 0;
+
+ READ_UNALIGNED(dbg, val, Dwarf_Unsigned, input_field, 2);
+ SIGN_EXTEND(val, 2);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + 2;
+ }
+ break;
+
+ case DW_EH_PE_sdata4:{
+ Dwarf_Unsigned val = 0;
+
+ /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
+ READ_UNALIGNED(dbg, val,
+ Dwarf_Unsigned, input_field,
+ sizeof(Dwarf_ufixed));
+ SIGN_EXTEND(val, sizeof(Dwarf_ufixed));
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ }
+ break;
+ case DW_EH_PE_sdata8:{
+ Dwarf_Unsigned val = 0;
+
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED(dbg, val,
+ Dwarf_Unsigned, input_field,
+ sizeof(Dwarf_Unsigned));
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ }
+ break;
+ default:
+ return DW_DLV_ERROR;
+
+ };
+ /* The ELF ABI for gnu does not document the meaning of
+ DW_EH_PE_pcrel, which is awkward. It apparently means the value
+ we got above is pc-relative (meaning section-relative), so we
+ adjust the value. Section_pointer may be null if it is known
+ DW_EH_PE_pcrel cannot apply, such as for .debug_frame or for an
+ address-range value. */
+ if (section_pointer && ((gnu_encoding & 0x70) == DW_EH_PE_pcrel)) {
+ /* Address (*addr) above is pc relative with respect to a
+ section. Add to the offset the base address (from elf) of
+ section and the distance of the field we are reading from
+ the section-beginning to get the actual address. */
+ /* ASSERT: input_field_original >= section_pointer */
+ Dwarf_Unsigned distance =
+ input_field_original - section_pointer;
+ *addr += dbg->de_debug_frame_eh_gnu.dss_addr + distance;
+ }
+
+ return DW_DLV_OK;
+}
+
+
+
+
+/*
+ All augmentation string checking done here now.
+
+ For .eh_frame, gcc from 3.3 uses the z style, earlier used
+ only "eh" as augmentation. We don't yet handle
+ decoding .eh_frame with the z style extensions like L P.
+
+ These are nasty heuristics, but then that's life
+ as augmentations are implementation specific.
+*/
+/* ARGSUSED */
+enum Dwarf_augmentation_type
+_dwarf_get_augmentation_type(Dwarf_Debug dbg,
+ Dwarf_Small * augmentation_string,
+ int is_gcc_eh_frame)
+{
+ enum Dwarf_augmentation_type t = aug_unknown;
+ char *ag_string = (char *) augmentation_string;
+
+ if (ag_string[0] == 0) {
+ /* Empty string. We'll just guess that we know what this means:
+ standard dwarf2/3 with no implementation-defined fields. */
+ t = aug_empty_string;
+ } else if (strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING) == 0) {
+ /* The string is "mti v1". Used internally at SGI, probably
+ never shipped. Replaced by "z". Treat like 'nothing
+ special'. */
+ t = aug_irix_mti_v1;
+ } else if (ag_string[0] == 'z') {
+ /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2
+ were designed as for IRIX CC, but never implemented */
+ /* If it's gcc, z may be any of several things. "z" or z
+ followed optionally followed by one or more of L R P, each
+ of which means a value may be present. Should be in eh_frame
+ only, I think. */
+ if (is_gcc_eh_frame) {
+ t = aug_gcc_eh_z;
+ } else if (ag_string[1] == 0) {
+ /* This is the normal IRIX C++ case, where there is an
+ offset into a table in each fde. The table being for
+ IRIX CC exception handling. */
+ /* DW_CIE_AUGMENTER_STRING_V0 "z" */
+ t = aug_irix_exception_table;
+ } /* Else unknown. */
+ } else if (strncmp(ag_string, "eh", 2) == 0) {
+ /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least
+ for x86. */
+ t = aug_eh;
+ } else if (strcmp(ag_string, "armcc+") == 0) {
+ /* Arm uses this string to mean a bug in
+ in Arm compilers was fixed, changing to the standard
+ calculation of the CFA. See
+ http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
+ for details. */
+ t = aug_armcc;
+ } else {
+
+ }
+ return t;
+}
+
+/* Using augmentation, and version
+ read in the augmentation data for GNU eh.
+
+ Return DW_DLV_OK if we succeeded,
+ DW_DLV_ERR if we fail.
+
+ On success, update 'size_of_augmentation_data' with
+ the length of the fields that are part of augmentation (so the
+ caller can increment frame_ptr appropriately).
+
+ 'frame_ptr' points within section.
+ 'section_pointer' points to section base address in memory.
+*/
+/* ARGSUSED */
+static int
+get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr,
+ unsigned long *size_of_augmentation_data,
+ enum Dwarf_augmentation_type augtype,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * fde_eh_encoding_out,
+ char *augmentation)
+{
+ char *suffix = 0;
+ unsigned long augdata_size = 0;
+
+ if (augtype == aug_gcc_eh_z) {
+ /* Has leading 'z'. */
+ Dwarf_Word leb128_length = 0;
+
+ /* Dwarf_Unsigned eh_value = */
+ _dwarf_decode_u_leb128(frame_ptr, &leb128_length);
+ augdata_size += leb128_length;
+ frame_ptr += leb128_length;
+ suffix = augmentation + 1;
+ } else {
+ /* Prefix is 'eh'. As in gcc 3.2. No suffix present
+ apparently. */
+ suffix = augmentation + 2;
+ }
+ for (; *suffix; ++suffix) {
+ /* We have no idea what this is as yet. Some extensions beyond
+ dwarf exist which we do not yet handle. */
+ return DW_DLV_ERROR;
+
+ }
+
+ *size_of_augmentation_data = augdata_size;
+ return DW_DLV_OK;
+}
+
+
+/* Make the 'cie_id_addr' consistent across .debug_frame and .eh_frame.
+ Calculate a pointer into section bytes given a cie_id, which is
+ trivial for .debug_frame, but a bit more work for .eh_frame.
+*/
+static Dwarf_Small *
+get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * cie_id_addr)
+{
+ Dwarf_Small *cieptr = 0;
+
+ if (use_gnu_cie_calc) {
+ /* cie_id value is offset, in section, of the cie_id itself, to
+ use vm ptr of the value, less the value, to get to the cie
+ itself. In addition, munge *cie_id_addr to look *as if* it
+ was from real dwarf. */
+ cieptr = (Dwarf_Small *)(uintptr_t)
+ ((Dwarf_Unsigned)(uintptr_t)cie_id_addr) -
+ ((Dwarf_Unsigned) cie_id_value);
+ } else {
+ /* Traditional dwarf section offset is in cie_id */
+ cieptr = (section_ptr + cie_id_value);
+ }
+ return cieptr;
+}
+
+/* To properly release all spaced used.
+ Earlier approaches (before July 15, 2005)
+ letting client do the dealloc directly left
+ some data allocated.
+ This is directly called by consumer code.
+*/
+void
+dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
+ Dwarf_Cie * cie_data,
+ Dwarf_Signed cie_element_count,
+ Dwarf_Fde * fde_data,
+ Dwarf_Signed fde_element_count)
+{
+ Dwarf_Signed i = 0;
+
+ for (i = 0; i < cie_element_count; ++i) {
+ Dwarf_Frame frame = cie_data[i]->ci_initial_table;
+
+ if (frame)
+ dwarf_dealloc(dbg, frame, DW_DLA_FRAME);
+ dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE);
+ }
+ for (i = 0; i < fde_element_count; ++i) {
+ dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE);
+ }
+ if (cie_data)
+ dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
+ if (fde_data)
+ dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
+
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame3.c b/usr/src/lib/libdwarf/common/dwarf_frame3.c
new file mode 100644
index 0000000000..7bd8ec86d5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame3.c
@@ -0,0 +1,290 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* using Arange as a way to build a list */
+
+/*
+ Used by rqs (an IRIX application).
+ Not needed except for that one application.
+ Should be moved to its own source file since
+ it is so rarely needed.
+ Returns DW_DLV_OK if returns the arrays.
+ Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?)
+ Returns DW_DLV_ERROR if there is an error.
+
+ Uses DW_FRAME_CFA_COL because IRIX is only DWARF2
+ and that is what IRIX compilers and compatible
+ compilers support on IRIX.
+*/
+int
+_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
+ Dwarf_Off ** offsetlist,
+ Dwarf_Signed * returncount,
+ Dwarf_Error * err)
+{
+ int retval = DW_DLV_OK;
+ int res = DW_DLV_ERROR;
+ Dwarf_Cie *cie_data;
+ Dwarf_Signed cie_count;
+ Dwarf_Fde *fde_data;
+ Dwarf_Signed fde_count;
+ Dwarf_Signed i;
+ Dwarf_Frame_Op *frame_inst;
+ Dwarf_Fde fdep;
+ Dwarf_Cie ciep;
+ Dwarf_Chain curr_chain = 0;
+ Dwarf_Chain head_chain = 0;
+ Dwarf_Chain prev_chain = 0;
+ Dwarf_Arange arange;
+ Dwarf_Unsigned arange_count = 0;
+ Dwarf_Addr *arange_addrs = 0;
+ Dwarf_Off *arange_offsets = 0;
+
+ res = dwarf_get_fde_list(dbg, &cie_data, &cie_count,
+ &fde_data, &fde_count, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ for (i = 0; i < cie_count; i++) {
+ Dwarf_Off instoff = 0;
+ Dwarf_Signed initial_instructions_length = 0;
+ Dwarf_Small *instr_end = 0;
+ Dwarf_Sword icount = 0;
+ int j = 0;
+ int dw_err;
+
+ ciep = cie_data[i];
+ instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data;
+ initial_instructions_length = ciep->ci_length +
+ ciep->ci_length_size + ciep->ci_extension_size -
+ (ciep->ci_cie_instr_start - ciep->ci_cie_start);
+ instr_end = ciep->ci_cie_instr_start +
+ initial_instructions_length;
+ res = _dwarf_exec_frame_instr( /* make_instr */ true,
+ &frame_inst,
+ /* search_pc= */ false,
+ /* search_pc_val= */ 0,
+ /* location */ 0,
+ ciep->ci_cie_instr_start,
+ instr_end,
+ /* Dwarf_frame= */ 0,
+ /* cie= */ 0,
+ dbg,
+ DW_FRAME_CFA_COL,
+ &icount, &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, err, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ continue;
+ }
+
+ for (j = 0; j < icount; ++j) {
+ Dwarf_Frame_Op *finst = frame_inst + j;
+
+ if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) {
+ /* is DW_CFA_set_loc */
+ Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset;
+ Dwarf_Off off = finst->fp_instr_offset + instoff;
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = add;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+ }
+ dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
+
+ }
+ for (i = 0; i < fde_count; i++) {
+ Dwarf_Small *instr_end = 0;
+ Dwarf_Sword icount = 0;
+ Dwarf_Signed instructions_length = 0;
+ Dwarf_Off instoff = 0;
+ Dwarf_Off off = 0;
+ Dwarf_Addr addr = 0;
+ int j = 0;
+ int dw_err;
+
+ fdep = fde_data[i];
+ off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data;
+ addr = fdep->fd_initial_location;
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = addr;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+
+ instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data;
+ instructions_length = fdep->fd_length +
+ fdep->fd_length_size + fdep->fd_extension_size -
+ (fdep->fd_fde_instr_start - fdep->fd_fde_start);
+ instr_end = fdep->fd_fde_instr_start + instructions_length;
+ res = _dwarf_exec_frame_instr( /* make_instr */ true,
+ &frame_inst,
+ /* search_pc= */ false,
+ /* search_pc_val= */ 0,
+ /* location */ 0,
+ fdep->fd_fde_instr_start,
+ instr_end,
+ /* Dwarf_frame= */ 0,
+ /* cie= */ 0,
+ dbg,
+ DW_FRAME_CFA_COL,
+ &icount, &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, err, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ continue;
+ }
+
+ for (j = 0; j < icount; ++j) {
+ Dwarf_Frame_Op *finst2 = frame_inst + j;
+
+ if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) {
+ /* is DW_CFA_set_loc */
+ Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset;
+ Dwarf_Off off = finst2->fp_instr_offset + instoff;
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = add;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+ }
+ }
+ dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
+
+ }
+ dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
+ dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
+ arange_addrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_addrs == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange_offsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_offsets == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ Dwarf_Arange ar = curr_chain->ch_item;
+
+ arange_addrs[i] = ar->ar_address;
+ arange_offsets[i] = ar->ar_info_offset;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+ *returncount = arange_count;
+ *offsetlist = arange_offsets;
+ *addrlist = arange_addrs;
+ return retval;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_funcs.c b/usr/src/lib/libdwarf/common/dwarf_funcs.c
new file mode 100644
index 0000000000..8d725ae33f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_funcs.c
@@ -0,0 +1,130 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_funcs.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_funcs(Dwarf_Debug dbg,
+ Dwarf_Func ** funcs,
+ Dwarf_Signed * ret_func_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_funcnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_funcnames.dss_data,
+ dbg->de_debug_funcnames.dss_size,
+ (Dwarf_Global **) funcs, /* Type punning for sections with identical format. */
+ ret_func_count,
+ error,
+ DW_DLA_FUNC_CONTEXT,
+ DW_DLA_FUNC,
+ DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_funcs_dealloc(Dwarf_Debug dbg, Dwarf_Func * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_FUNC_CONTEXT,
+ DW_DLA_FUNC, DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_funcname(Dwarf_Func func_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ if (func == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FUNC_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (func->gl_name);
+ return DW_DLV_OK;
+}
+
+int
+dwarf_func_die_offset(Dwarf_Func func_in,
+ Dwarf_Off * return_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_die_offset(func, return_offset, error);
+}
+
+
+int
+dwarf_func_cu_offset(Dwarf_Func func_in,
+ Dwarf_Off * return_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_cu_offset(func, return_offset, error);
+}
+
+
+int
+dwarf_func_name_offsets(Dwarf_Func func_in,
+ char **ret_func_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_name_offsets(func,
+ ret_func_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_funcs.h b/usr/src/lib/libdwarf/common/dwarf_funcs.h
new file mode 100644
index 0000000000..bf91c32157
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_funcs.h
@@ -0,0 +1,42 @@
+/*
+
+ Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+typedef struct Dwarf_Func_Context_s *Dwarf_Func_Context;
+
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_global.c b/usr/src/lib/libdwarf/common/dwarf_global.c
new file mode 100644
index 0000000000..d1c090fa43
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_global.c
@@ -0,0 +1,607 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_global.h"
+
+
+#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */
+/* The 'fixup' here intended for IRIX targets only.
+ With a 2+GB Elf64 IRIX executable (under 4GB in size),
+ some DIE offsets wrongly
+ got the 32bit upper bit sign extended. For the cu-header
+ offset in the .debug_pubnames section and in the
+ .debug_aranges section.
+ the 'varp' here is a pointer to an offset into .debug_info.
+ We fix up the offset here if it seems advisable..
+
+ As of June 2005 we have identified a series of mistakes
+ in ldx64 that can cause this (64 bit values getting passed
+ thru 32-bit signed knothole).
+*/
+void
+_dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
+ Dwarf_Unsigned * varp, char *caller_site_name)
+{
+
+ Dwarf_Unsigned var = *varp;
+
+#define UPPER33 0xffffffff80000000LL
+#define LOWER32 0xffffffffLL
+ /* Restrict the hack to the known case. Upper 32 bits erroneously
+ sign extended from lower 32 upper bit. */
+ if ((var & UPPER33) == UPPER33) {
+ var &= LOWER32;
+ /* Apply the fix. Dreadful hack. */
+ *varp = var;
+ }
+#undef UPPER33
+#undef LOWER32
+ return;
+}
+#endif
+
+
+int
+dwarf_get_globals(Dwarf_Debug dbg,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_pubnames.dss_data,
+ dbg->de_debug_pubnames.dss_size,
+ globals,
+ return_count,
+ error,
+ DW_DLA_GLOBAL_CONTEXT,
+ DW_DLA_GLOBAL,
+ DW_DLE_PUBNAMES_LENGTH_BAD,
+ DW_DLE_PUBNAMES_VERSION_ERROR);
+
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, dwgl,
+ count,
+ DW_DLA_GLOBAL_CONTEXT,
+ DW_DLA_GLOBAL, DW_DLA_LIST);
+ return;
+}
+
+void
+_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
+ Dwarf_Signed count,
+ int context_code,
+ int global_code, int list_code)
+{
+ Dwarf_Signed i;
+ struct Dwarf_Global_Context_s *gcp = 0;
+ struct Dwarf_Global_Context_s *lastgcp = 0;
+
+ for (i = 0; i < count; i++) {
+ Dwarf_Global dgb = dwgl[i];
+
+ gcp = dgb->gl_context;
+
+ if (lastgcp != gcp) {
+ lastgcp = gcp;
+ dwarf_dealloc(dbg, gcp, context_code);
+ }
+ dwarf_dealloc(dbg, dgb, global_code);
+ }
+ dwarf_dealloc(dbg, dwgl, list_code);
+ return;
+}
+
+
+/* Sweeps the complete section.
+*/
+int
+_dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
+ Dwarf_Small * section_data_ptr,
+ Dwarf_Unsigned section_length,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count,
+ Dwarf_Error * error,
+ int context_code,
+ int global_code,
+ int length_err_num,
+ int version_err_num)
+{
+
+
+ Dwarf_Small *pubnames_like_ptr = 0;
+
+
+
+ /* Points to the context for the current set of global names, and
+ contains information to identify the compilation-unit that the
+ set refers to. */
+ Dwarf_Global_Context pubnames_context = 0;
+
+ Dwarf_Half version = 0;
+
+ /*
+ Offset from the start of compilation-unit for the current
+ global. */
+ Dwarf_Off die_offset_in_cu = 0;
+
+ Dwarf_Unsigned global_count = 0;
+
+ /* Points to the current global read. */
+ Dwarf_Global global = 0;
+
+ /* Used to chain the Dwarf_Global_s structs for creating contiguous
+ list of pointers to the structs. */
+ Dwarf_Chain curr_chain = 0;
+ Dwarf_Chain prev_chain = 0;
+ Dwarf_Chain head_chain = 0;
+
+ /* Points to contiguous block of Dwarf_Global's to be returned. */
+ Dwarf_Global *ret_globals = 0;
+
+ /* Temporary counter. */
+ Dwarf_Unsigned i = 0;
+
+
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /* We will eventually need the .debug_info data. Load it now. */
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ if (section_data_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ pubnames_like_ptr = section_data_ptr;
+ do {
+ Dwarf_Unsigned length = 0;
+ int local_extension_size = 0;
+ int local_length_size = 0;
+
+ /* Some compilers emit padding at the end of each cu's area.
+ pubnames_ptr_past_end_cu records the true area end for this
+ cu's data. Essentially the length in the header and the 0
+ terminator of the data are redundant information. The
+ dwarf2/3 spec does not mention what to do if the length is
+ past the 0 terminator. So we take any bytes left after the 0
+ as padding and ignore them. */
+ Dwarf_Small *pubnames_ptr_past_end_cu = 0;
+
+
+ pubnames_context = (Dwarf_Global_Context)
+ _dwarf_get_alloc(dbg, context_code, 1);
+ if (pubnames_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed
+ bytes. */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ pubnames_like_ptr, local_length_size,
+ local_extension_size);
+ pubnames_context->pu_length_size = local_length_size;
+ pubnames_context->pu_extension_size = local_extension_size;
+ pubnames_context->pu_dbg = dbg;
+
+ pubnames_ptr_past_end_cu = pubnames_like_ptr + length;
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ pubnames_like_ptr, sizeof(Dwarf_Half));
+ pubnames_like_ptr += sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP) {
+ _dwarf_error(dbg, error, version_err_num);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Offset of CU header in debug section. */
+ READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header,
+ Dwarf_Off, pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ pubnames_context->pu_offset_of_cu_header,
+ "pubnames cu header offset");
+
+
+ READ_UNALIGNED(dbg, pubnames_context->pu_info_length,
+ Dwarf_Unsigned, pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+
+ if (pubnames_like_ptr > (section_data_ptr + section_length)) {
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Read initial offset (of DIE within CU) of a pubname, final
+ entry is not a pair, just a zero offset. */
+ READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
+ pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ die_offset_in_cu, "offset of die in cu");
+
+ /* Loop thru pairs. DIE off with CU followed by string. */
+ while (die_offset_in_cu != 0) {
+
+ /* Already read offset, pubnames_like_ptr now points to the
+ string. */
+ global =
+ (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1);
+ if (global == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ global_count++;
+
+ global->gl_context = pubnames_context;
+
+ global->gl_named_die_offset_within_cu = die_offset_in_cu;
+
+ global->gl_name = pubnames_like_ptr;
+
+ pubnames_like_ptr = pubnames_like_ptr +
+ strlen((char *) pubnames_like_ptr) + 1;
+
+
+ /* finish off current entry chain */
+ curr_chain =
+ (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Put current global on singly_linked list. */
+ curr_chain->ch_item = (Dwarf_Global) global;
+
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+ /* read offset for the *next* entry */
+ READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
+ pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ die_offset_in_cu,
+ "offset of next die in cu");
+
+ if (pubnames_like_ptr > (section_data_ptr + section_length)) {
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+ }
+ /* ASSERT: die_offset_in_cu == 0 */
+ if (pubnames_like_ptr > pubnames_ptr_past_end_cu) {
+ /* This is some kind of error. This simply cannot happen.
+ The encoding is wrong or the length in the header for
+ this cu's contribution is wrong. */
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+ /* If there is some kind of padding at the end of the section,
+ as emitted by some compilers, skip over that padding and
+ simply ignore the bytes thus passed-over. With most
+ compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at
+ this point */
+ pubnames_like_ptr = pubnames_ptr_past_end_cu;
+
+ } while (pubnames_like_ptr < (section_data_ptr + section_length));
+
+ /* Points to contiguous block of Dwarf_Global's. */
+ ret_globals = (Dwarf_Global *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
+ if (ret_globals == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /*
+ Store pointers to Dwarf_Global_s structs in contiguous block,
+ and deallocate the chain. */
+ curr_chain = head_chain;
+ for (i = 0; i < global_count; i++) {
+ *(ret_globals + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *globals = ret_globals;
+ *return_count = (Dwarf_Signed) global_count;
+ return DW_DLV_OK;
+}
+
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_name pointer
+ a pointer to the string which is the entry name.
+
+*/
+int
+dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error)
+{
+ if (glob == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (glob->gl_name);
+ return DW_DLV_OK;
+}
+
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_off pointer the
+ global offset of the DIE for this entry.
+ The global offset is the offset within the .debug_info
+ section as a whole.
+*/
+int
+dwarf_global_die_offset(Dwarf_Global global,
+ Dwarf_Off * ret_off, Dwarf_Error * error)
+{
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (global->gl_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_off = (global->gl_named_die_offset_within_cu +
+ global->gl_context->pu_offset_of_cu_header);
+ return DW_DLV_OK;
+}
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_off pointer the
+ offset of the compilation unit header of the
+ compilation unit the global is part of.
+
+ In early versions of this, the value returned was
+ the offset of the compilation unit die, and
+ other cu-local die offsets were faked so adding this to
+ such a cu-local offset got a true section offset.
+ Now things do as they say (adding *cu_header_offset to
+ a cu-local offset gets the section offset).
+
+*/
+int
+dwarf_global_cu_offset(Dwarf_Global global,
+ Dwarf_Off * cu_header_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global_Context con = 0;
+
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ con = global->gl_context;
+
+ if (con == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* In early libdwarf, this incorrectly returned the offset of the
+ CU DIE. Now correctly returns the header offset. */
+ *cu_header_offset = con->pu_offset_of_cu_header;
+
+ return DW_DLV_OK;
+}
+
+/*
+ Give back the pubnames entry (or any other like section)
+ name, symbol DIE offset, and the cu-DIE offset.
+
+ Various errors are possible.
+
+ The string pointer returned thru ret_name is not
+ dwarf_get_alloc()ed, so no dwarf_dealloc()
+ DW_DLA_STRING should be applied to it.
+
+*/
+int
+dwarf_global_name_offsets(Dwarf_Global global,
+ char **ret_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global_Context con = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Off off = 0;
+
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ con = global->gl_context;
+
+ if (con == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ off = con->pu_offset_of_cu_header;
+ /* The offset had better not be too close to the end. If it is,
+ _dwarf_length_of_cu_header() will step off the end and therefore
+ must not be used. 10 is a meaningless heuristic, but no CU
+ header is that small so it is safe. An erroneous offset is due
+ to a bug in the tool chain. A bug like this has been seen on
+ IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and
+ with 2 million pubnames entries. */
+#define MIN_CU_HDR_SIZE 10
+ dbg = con->pu_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (dbg->de_debug_info.dss_size &&
+ ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) {
+ _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+#undef MIN_CU_HDR_SIZE
+ if (die_offset != NULL) {
+ *die_offset = global->gl_named_die_offset_within_cu + off;
+ }
+
+ *ret_name = (char *) global->gl_name;
+
+ if (cu_die_offset != NULL) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ /* The offset had better not be too close to the end. If it is,
+ _dwarf_length_of_cu_header() will step off the end and
+ therefore must not be used. 10 is a meaningless heuristic,
+ but no CU header is that small so it is safe. */
+ if ((off + 10) >= dbg->de_debug_info.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off);
+ }
+
+
+ return DW_DLV_OK;
+}
+
+/*
+ We have the offset to a CU header.
+ Return thru outFileOffset the offset of the CU DIE.
+
+ New June, 2001.
+ Used by SGI debuggers.
+ No error is possible.
+
+ See also dwarf_CU_dieoffset_given_die().
+*/
+
+/* ARGSUSED */
+int
+dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
+ Dwarf_Off in_cu_header_offset,
+ Dwarf_Off * out_cu_die_offset,
+ Dwarf_Error * err)
+{
+ Dwarf_Off len =
+ _dwarf_length_of_cu_header(dbg, in_cu_header_offset);
+
+ Dwarf_Off newoff = in_cu_header_offset + len;
+
+ *out_cu_die_offset = newoff;
+ return DW_DLV_OK;
+}
+/* dwarf_CU_dieoffset_given_die returns
+ the global debug_info section offset of the CU die
+ that is the CU containing the given (passed-in) die.
+ This information makes it possible for a consumer to
+ find and print context information for any die.
+
+ Use dwarf_offdie() passing in the offset this returns
+ to get a die pointer to the CU die.
+ */
+int
+dwarf_CU_dieoffset_given_die(Dwarf_Die die,
+ Dwarf_Off* return_offset,
+ Dwarf_Error* error)
+{
+ Dwarf_Off dieoff = 0;
+ Dwarf_CU_Context cucontext = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cucontext = die->di_cu_context;
+ dieoff = cucontext->cc_debug_info_offset;
+ /* The following call cannot fail, so no error check. */
+ dwarf_get_cu_die_offset_given_cu_header_offset(
+ cucontext->cc_dbg, dieoff, return_offset,error);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_global.h b/usr/src/lib/libdwarf/common/dwarf_global.h
new file mode 100644
index 0000000000..c2bc2cdcc3
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_global.h
@@ -0,0 +1,124 @@
+/*
+
+ Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+typedef struct Dwarf_Global_Context_s *Dwarf_Global_Context;
+
+/*
+ This struct contains header information for a set of pubnames.
+ Essentially, they contain the context for a set of pubnames
+ belonging to a compilation-unit.
+
+ This is also used for the sgi-specific
+ weaknames, typenames, varnames, funcnames data:
+ the structs for those are incomplete and
+ instances of this are used instead.
+
+ Also used for DWARF3 .debug_pubtypes.
+
+*/
+struct Dwarf_Global_Context_s {
+
+ /* Length in .debug_pubnames (etc) of a set of names for a
+ compilation-unit. Dwarf_Word pu_length; The value is not made
+ available outside libdwarf and not used inside, so no need to
+ record it. */
+
+ /* For this context, size of a length. 4 or 8 */
+ unsigned char pu_length_size;
+
+ /* For this CU, size of the extension 0 except for dwarf2 extension
+ 64bit, in which case is 4. */
+ unsigned char pu_extension_size;
+
+ /*
+ Offset into .debug_info of the compilation-unit header (not DIE)
+ for this set of pubnames. */
+ Dwarf_Off pu_offset_of_cu_header;
+
+ /* Size of compilation-unit that these pubnames are in. */
+ Dwarf_Unsigned pu_info_length;
+
+ Dwarf_Debug pu_dbg;
+};
+
+
+/* This struct contains information for a single pubname. */
+struct Dwarf_Global_s {
+
+ /*
+ Offset from the start of the corresponding compilation-unit of
+ the DIE for the given pubname CU. */
+ Dwarf_Off gl_named_die_offset_within_cu;
+
+ /* Points to the given pubname. */
+ Dwarf_Small *gl_name;
+
+ /* Context for this pubname. */
+ Dwarf_Global_Context gl_context;
+};
+
+int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
+ Dwarf_Small *
+ section_data_ptr,
+ Dwarf_Unsigned
+ section_length,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count,
+ Dwarf_Error * error,
+ int context_code,
+ int global_code,
+ int length_err_num,
+ int version_err_num);
+
+void
+_dwarf_internal_globals_dealloc( Dwarf_Debug dbg, Dwarf_Global *dwgl,
+ Dwarf_Signed count,
+ int context_code,
+ int global_code,
+ int list_code);
+
+
+#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */
+void _dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
+ Dwarf_Unsigned *varp,
+ char *caller_site_name);
+#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) _dwarf_fix_up_offset_irix(ldbg,&var,name)
+#else
+#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name)
+#endif
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_harmless.c b/usr/src/lib/libdwarf/common/dwarf_harmless.c
new file mode 100644
index 0000000000..16dbe4bc97
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_harmless.c
@@ -0,0 +1,226 @@
+/*
+
+ Copyright (C) 2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+*/
+
+/*
+ This implements _dwarf_insert_harmless_error
+ and related helper functions for recording
+ compiler errors that need not make the input
+ unusable.
+
+ Applications can use dwarf_get_harmless_error_list to
+ find (and possibly print) a warning about such errors.
+
+ The initial error reported here is
+ DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a
+ bug in a specific compiler.
+
+ It is a fixed length circular list to constrain
+ the space used for errors.
+
+ The assumption is that these errors are exceedingly
+ rare, and indicate a broken compiler (the one that
+ produced the object getting the error(s)).
+
+ dh_maxcount is recorded internally as 1 greater than
+ requested. Hiding the fact we always leave one
+ slot unused (at least). So a user request for
+ N slots really gives the user N usable slots.
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_frame.h"
+#include "dwarf_harmless.h"
+
+
+/* The pointers returned here through errmsg_ptrs_array
+ become invalidated by any call to libdwarf. Any call.
+*/
+int dwarf_get_harmless_error_list(Dwarf_Debug dbg,
+ unsigned count,
+ const char ** errmsg_ptrs_array,
+ unsigned * errs_count)
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ if(!dhp->dh_errors) {
+ dhp->dh_errs_count = 0;
+ return DW_DLV_NO_ENTRY;
+ }
+ if(dhp->dh_errs_count == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ if(errs_count) {
+ *errs_count = dhp->dh_errs_count;
+ }
+ if(count) {
+ /* NULL terminate the array of pointers */
+ --count;
+ errmsg_ptrs_array[count] = 0;
+
+ if(dhp->dh_next_to_use != dhp->dh_first) {
+ unsigned i = 0;
+ unsigned cur = dhp->dh_first;
+ for(i = 0; cur != dhp->dh_next_to_use; ++i) {
+ if(i >= count ) {
+ /* All output spaces are used. */
+ break;
+ }
+ errmsg_ptrs_array[i] = dhp->dh_errors[cur];
+ cur = (cur +1) % dhp->dh_maxcount;
+ }
+ errmsg_ptrs_array[i] = 0;
+ }
+ }
+ dhp->dh_next_to_use = 0;
+ dhp->dh_first = 0;
+ dhp->dh_errs_count = 0;
+ return DW_DLV_OK;
+}
+
+/* strncpy does not null-terminate, this does it. */
+static void
+safe_strncpy(char *targ, char *src, unsigned spaceavail)
+{
+ unsigned goodcount = spaceavail-1;
+ if(spaceavail < 1) {
+ return; /* impossible */
+ }
+ strncpy(targ,src,goodcount);
+ targ[goodcount] = 0;
+}
+
+/* Insertion made public is only for testing the harmless error code,
+ it is not necessarily useful for libdwarf client code aside
+ from code testing libdwarf. */
+void dwarf_insert_harmless_error(Dwarf_Debug dbg,
+ char *newerror)
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ unsigned next = 0;
+ unsigned cur = dhp->dh_next_to_use;
+ char *msgspace;
+ if(!dhp->dh_errors) {
+ dhp->dh_errs_count++;
+ return;
+ }
+ msgspace = dhp->dh_errors[cur];
+ safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE);
+ next = (cur+1) % dhp->dh_maxcount;
+ dhp->dh_errs_count++;
+ dhp->dh_next_to_use = next;
+ if (dhp->dh_next_to_use == dhp->dh_first) {
+ /* Array is full set full invariant. */
+ dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount;
+ }
+}
+
+/* The size of the circular list of strings may be set
+ and reset as desired. Returns the previous size of
+ the list. If the list is shortened excess error entries
+ are simply dropped.
+ If the reallocation fails the list size is left unchanged.
+ Do not make this a long list!
+
+ Remember the maxcount we record is 1 > the user count,
+ so we adjust it so it looks like the user count.
+*/
+unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,
+ unsigned maxcount )
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ unsigned prevcount = dhp->dh_maxcount;
+ if(maxcount != 0) {
+ ++maxcount;
+ if(maxcount != dhp->dh_maxcount) {
+ /* Assign transfers 'ownership' of the malloc areas
+ to oldarray. */
+ struct Dwarf_Harmless_s oldarray = *dhp;
+ /* Do not double increment the max, the init() func
+ increments it too. */
+ dwarf_harmless_init(dhp,maxcount-1);
+ if(oldarray.dh_next_to_use != oldarray.dh_first) {
+ unsigned i = 0;
+ for(i = oldarray.dh_first; i != oldarray.dh_next_to_use;
+ i = (i+1)%oldarray.dh_maxcount) {
+ dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]);
+ }
+ if( oldarray.dh_errs_count > dhp->dh_errs_count) {
+ dhp->dh_errs_count = oldarray.dh_errs_count;
+ }
+ }
+ dwarf_harmless_cleanout(&oldarray);
+ }
+ }
+ return prevcount-1;
+}
+
+void
+dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size)
+{
+ unsigned i = 0;
+ memset(dhp,0,sizeof(*dhp));
+ dhp->dh_maxcount = size +1;
+ dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount);
+ if (!dhp->dh_errors) {
+ dhp->dh_maxcount = 0;
+ return;
+ }
+
+ for(i = 0; i < dhp->dh_maxcount; ++i) {
+ char *newstr =
+ (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE);
+ dhp->dh_errors[i] = newstr;
+ if(!newstr) {
+ dhp->dh_maxcount = 0;
+ /* Let it leak, the leak is a constrained amount. */
+ dhp->dh_errors = 0;
+ return;
+ }
+ /* We make the string content well-defined by an initial
+ NUL byte, but this is not really necessary. */
+ newstr[0] = 0;
+ }
+}
+
+void
+dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp)
+{
+ unsigned i = 0;
+ if(!dhp->dh_errors) {
+ return;
+ }
+ for(i = 0; i < dhp->dh_maxcount; ++i) {
+ free(dhp->dh_errors[i]);
+ }
+ free(dhp->dh_errors);
+ dhp->dh_errors = 0;
+ dhp->dh_maxcount = 0;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_harmless.h b/usr/src/lib/libdwarf/common/dwarf_harmless.h
new file mode 100644
index 0000000000..3d4d910ce9
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_harmless.h
@@ -0,0 +1,31 @@
+/*
+
+ Copyright (C) 2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+*/
+
+
+
+void dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size);
+void dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp);
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_incl.h b/usr/src/lib/libdwarf/common/dwarf_incl.h
new file mode 100644
index 0000000000..df2fbf334c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_incl.h
@@ -0,0 +1,66 @@
+/*
+
+ Copyright (C) 2000, 2002, 2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#ifndef DWARF_INCL_H
+#define DWARF_INCL_H
+#if (!defined(HAVE_RAW_LIBELF_OK) && defined(HAVE_LIBELF_OFF64_OK) )
+/* At a certain point libelf.h requires _GNU_SOURCE.
+ here we assume the criteria in configure determine that
+ usefully.
+*/
+#define _GNU_SOURCE 1
+#endif
+
+
+#include "libdwarfdefs.h"
+#include <string.h>
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <limits.h>
+#include <dwarf.h>
+#include <libdwarf.h>
+
+#include "dwarf_base_types.h"
+#include "dwarf_alloc.h"
+#include "dwarf_opaque.h"
+#include "dwarf_error.h"
+#include "dwarf_util.h"
+#endif /* DWARF_INCL_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_init_finish.c b/usr/src/lib/libdwarf/common/dwarf_init_finish.c
new file mode 100644
index 0000000000..1ab9d5fd38
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_init_finish.c
@@ -0,0 +1,577 @@
+/*
+
+ Copyright (C) 2000,2002,2003,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+#include "config.h"
+#include "dwarf_incl.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dwarf_incl.h"
+#include "malloc_check.h"
+
+#define DWARF_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_error(dbg, error, errval); return(retval);
+
+#define FALSE 0
+#define TRUE 1
+
+
+
+/* This static is copied to the dbg on dbg init
+ so that the static need not be referenced at
+ run time, preserving better locality of
+ reference.
+ Value is 0 means do the string check.
+ Value non-zero means do not do the check.
+*/
+static Dwarf_Small _dwarf_assume_string_bad;
+static Dwarf_Small _dwarf_apply_relocs = 1;
+
+/* Call this after calling dwarf_init but before doing anything else.
+ * It applies to all objects, not just the current object.
+ */
+int
+dwarf_set_reloc_application(int apply)
+{
+ int oldval = _dwarf_apply_relocs;
+ _dwarf_apply_relocs = apply;
+ return oldval;
+}
+
+int
+dwarf_set_stringcheck(int newval)
+{
+ int oldval = _dwarf_assume_string_bad;
+
+ _dwarf_assume_string_bad = newval;
+ return oldval;
+}
+
+/* Unifies the basic duplicate/empty testing and section
+ * data setting to one place. */
+static int
+get_basic_section_data(Dwarf_Debug dbg,
+ struct Dwarf_Section_s *secdata,
+ struct Dwarf_Obj_Access_Section_s *doas,
+ Dwarf_Half section_index,
+ Dwarf_Error* error,
+ int duperr, int emptyerr )
+{
+ if (secdata->dss_index != 0) {
+ DWARF_DBG_ERROR(dbg, duperr, DW_DLV_ERROR);
+ }
+ if (doas->size == 0) {
+ if (emptyerr == 0 ) {
+ /* Allow empty section. */
+ return DW_DLV_OK;
+ }
+ /* Know no reason to allow section */
+ DWARF_DBG_ERROR(dbg, emptyerr, DW_DLV_ERROR);
+ }
+ secdata->dss_index = section_index;
+ secdata->dss_size = doas->size;
+ secdata->dss_addr = doas->addr;
+ secdata->dss_link = doas->link;
+ return DW_DLV_OK;
+}
+
+
+static void
+add_rela_data( struct Dwarf_Section_s *secdata,
+ struct Dwarf_Obj_Access_Section_s *doas,
+ Dwarf_Half section_index)
+{
+ secdata->dss_reloc_index = section_index;
+ secdata->dss_reloc_size = doas->size;
+ secdata->dss_reloc_addr = doas->addr;
+ secdata->dss_reloc_symtab = doas->link;
+ secdata->dss_reloc_link = doas->link;
+}
+
+/*
+ Given an Elf ptr, set up dbg with pointers
+ to all the Dwarf data sections.
+ Return NULL on error.
+
+ This function is also responsible for determining
+ whether the given object contains Dwarf information
+ or not. The test currently used is that it contains
+ either a .debug_info or a .debug_frame section. If
+ not, it returns DW_DLV_NO_ENTRY causing dwarf_init() also to
+ return DW_DLV_NO_ENTRY. Earlier, we had thought of using only
+ the presence/absence of .debug_info to test, but we
+ added .debug_frame since there could be stripped objects
+ that have only a .debug_frame section for exception
+ processing.
+ DW_DLV_NO_ENTRY or DW_DLV_OK or DW_DLV_ERROR
+*/
+static int
+_dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ const char *scn_name = 0;
+ int foundDwarf = 0;
+ struct Dwarf_Obj_Access_Interface_s * obj = 0;
+
+ Dwarf_Endianness endianness;
+
+ Dwarf_Unsigned section_size = 0;
+ Dwarf_Unsigned section_count = 0;
+ Dwarf_Half section_index = 0;
+ Dwarf_Addr section_addr = 0;
+
+ foundDwarf = FALSE;
+
+ dbg->de_assume_string_in_bounds = _dwarf_assume_string_bad;
+
+ dbg->de_same_endian = 1;
+ dbg->de_copy_word = memcpy;
+ obj = dbg->de_obj_file;
+ endianness = obj->methods->get_byte_order(obj->object);
+#ifdef WORDS_BIGENDIAN
+ dbg->de_big_endian_object = 1;
+ if (endianness == DW_OBJECT_LSB ) {
+ dbg->de_same_endian = 0;
+ dbg->de_big_endian_object = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#else /* little endian */
+ dbg->de_big_endian_object = 0;
+ if (endianness == DW_OBJECT_MSB ) {
+ dbg->de_same_endian = 0;
+ dbg->de_big_endian_object = 1;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#endif /* !WORDS_BIGENDIAN */
+
+
+ /* The following de_length_size is Not Too Significant. Only used
+ one calculation, and an approximate one at that. */
+ dbg->de_length_size = obj->methods->get_length_size(obj->object);
+ dbg->de_pointer_size = obj->methods->get_pointer_size(obj->object);
+
+ section_count = obj->methods->get_section_count(obj->object);
+
+ /* We can skip index 0 when considering ELF files, but not other
+ object types. */
+ for (section_index = 0; section_index < section_count;
+ ++section_index) {
+
+ struct Dwarf_Obj_Access_Section_s doas;
+ int res = DW_DLV_ERROR;
+ int err;
+
+ res = obj->methods->get_section_info(obj->object,
+ section_index,
+ &doas, &err);
+ if(res == DW_DLV_ERROR){
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+
+ section_addr = doas.addr;
+ section_size = doas.size;
+ scn_name = doas.name;
+
+ if (strncmp(scn_name, ".debug_", 7)
+ && strcmp(scn_name, ".eh_frame")
+ && strcmp(scn_name, ".symtab")
+ && strcmp(scn_name, ".strtab")
+ && strncmp(scn_name, ".rela.",6)) {
+ continue;
+ }
+ else if (strcmp(scn_name, ".debug_info") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_info, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_INFO_DUPLICATE,DW_DLE_DEBUG_INFO_NULL);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".debug_abbrev") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_abbrev, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_ABBREV_DUPLICATE,DW_DLE_DEBUG_ABBREV_NULL);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_aranges") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_aranges, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_ARANGES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ else if (strcmp(scn_name, ".debug_line") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_line, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_LINE_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_frame") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_frame, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FRAME_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ } else if (strcmp(scn_name, ".eh_frame") == 0) {
+ /* gnu egcs-1.1.2 data */
+ res = get_basic_section_data(dbg,&dbg->de_debug_frame_eh_gnu, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FRAME_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".debug_loc") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_loc, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_LOC_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_pubnames") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_pubnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_PUBNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ else if (strcmp(scn_name, ".debug_str") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_str, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_STR_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_funcnames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_funcnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FUNCNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_typenames") == 0) {
+ /* SGI IRIX-only, created years before DWARF3. Content
+ essentially identical to .debug_pubtypes. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_typenames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_TYPENAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ } else if (strcmp(scn_name, ".debug_pubtypes") == 0) {
+ /* Section new in DWARF3. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_pubtypes, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_PUBTYPES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_varnames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_varnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_VARNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_weaknames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_weaknames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_WEAKNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ } else if (strcmp(scn_name, ".debug_macinfo") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_macinfo, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_MACINFO_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_ranges") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_ranges, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_RANGES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".symtab") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_elf_symtab, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_SYMTAB_ERR,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".strtab") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_elf_strtab, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_STRTAB_ERR,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strncmp(scn_name, ".rela.debug_",12) == 0) {
+ const char *rcn_name = scn_name + 5;
+ if (strcmp(rcn_name, ".debug_info") == 0) {
+ add_rela_data(&dbg->de_debug_info,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_abbrev") == 0) {
+ add_rela_data(&dbg->de_debug_abbrev,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_aranges") == 0) {
+ add_rela_data(&dbg->de_debug_aranges,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_line") == 0) {
+ add_rela_data(&dbg->de_debug_line,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_frame") == 0) {
+ add_rela_data(&dbg->de_debug_frame,&doas,section_index);
+ } else if (strcmp(rcn_name, ".eh_frame") == 0) {
+ add_rela_data(&dbg->de_debug_frame_eh_gnu,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_loc") == 0) {
+ add_rela_data(&dbg->de_debug_loc,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_pubnames") == 0) {
+ add_rela_data(&dbg->de_debug_pubnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_str") == 0) {
+ add_rela_data(&dbg->de_debug_str,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_funcnames") == 0) {
+ add_rela_data(&dbg->de_debug_funcnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_typenames") == 0) {
+ add_rela_data(&dbg->de_debug_typenames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_pubtypes") == 0) {
+ add_rela_data(&dbg->de_debug_pubtypes,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_varnames") == 0) {
+ add_rela_data(&dbg->de_debug_varnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_weaknames") == 0) {
+ add_rela_data(&dbg->de_debug_weaknames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_macinfo") == 0) {
+ add_rela_data(&dbg->de_debug_macinfo,&doas,section_index);
+ }
+ }
+ }
+ if (foundDwarf) {
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+/*
+ Use a Dwarf_Obj_Access_Interface to kick things off. All other
+ init routines eventually use this one.
+ The returned Dwarf_Debug contains a copy of *obj
+ the callers copy of *obj may be freed whenever the caller
+ wishes.
+*/
+int
+dwarf_object_init(Dwarf_Obj_Access_Interface* obj, Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Debug* ret_dbg,
+ Dwarf_Error* error)
+{
+ Dwarf_Debug dbg = 0;
+ int setup_result = DW_DLV_OK;
+
+ dbg = _dwarf_get_debug();
+ if (dbg == NULL) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
+ dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM;
+#ifdef HAVE_OLD_FRAME_CFA_COL
+ /* DW_FRAME_CFA_COL is really only suitable for old libdwarf frame
+ interfaces and its value of 0 there is only usable where
+ (as in MIPS) register 0 has no value other than 0 so
+ we can use the frame table column 0 for the CFA value
+ (and rely on client software to know when 'register 0'
+ is the cfa and when to just use a value 0 for register 0).
+ */
+ dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL;
+#else
+ dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL3;
+#endif
+ dbg->de_frame_same_value_number = DW_FRAME_SAME_VAL;
+ dbg->de_frame_undefined_value_number = DW_FRAME_UNDEFINED_VAL;
+
+ dbg->de_obj_file = obj;
+
+ setup_result = _dwarf_setup(dbg, error);
+ if (setup_result != DW_DLV_OK) {
+ /* The status we want to return here is of _dwarf_setup,
+ not of the _dwarf_free_all_of_one_debug(dbg) call.
+ So use a local status variable for the free. */
+ int freeresult = _dwarf_free_all_of_one_debug(dbg);
+ if (freeresult == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dwarf_malloc_check_complete("After Final free");
+ return setup_result;
+ }
+
+ dwarf_harmless_init(&dbg->de_harmless_errors,
+ DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE);
+
+ /* This call cannot fail: allocates nothing, releases nothing */
+ _dwarf_setup_debug(dbg);
+
+
+ *ret_dbg = dbg;
+ return DW_DLV_OK;
+}
+
+
+/*
+ A finish routine that is completely unaware of ELF.
+
+ Frees all memory that was not previously freed by
+ dwarf_dealloc.
+ Aside frmo certain categories.
+ */
+int
+dwarf_object_finish(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ int res = DW_DLV_OK;
+
+ res = _dwarf_free_all_of_one_debug(dbg);
+ if (res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dwarf_malloc_check_complete("After Final free");
+
+ return res;
+}
+
+
+/*
+ Load the ELF section with the specified index and set the
+ pointer pointed to by section_data to the memory where it
+ was loaded.
+ */
+int
+_dwarf_load_section(Dwarf_Debug dbg,
+ struct Dwarf_Section_s *section,
+ Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+ int err = 0;
+ struct Dwarf_Obj_Access_Interface_s *o = 0;
+
+ /* check to see if the section is already loaded */
+ if (section->dss_data != NULL) {
+ return DW_DLV_OK;
+ }
+ o = dbg->de_obj_file;
+ res = o->methods->load_section(
+ o->object, section->dss_index,
+ &section->dss_data, &err);
+ if(res == DW_DLV_ERROR){
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+ if(_dwarf_apply_relocs == 0) {
+ return res;
+ }
+ if(section->dss_reloc_size == 0) {
+ return res;
+ }
+ if(!o->methods->relocate_a_section) {
+ return res;
+ }
+ /*apply relocations */
+ res = o->methods->relocate_a_section( o->object, section->dss_index,
+ dbg, &err);
+ if(res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+ return res;
+}
+
+/* This is a hack so clients can verify offsets.
+ Added April 2005 so that debugger can detect broken offsets
+ (which happened in an IRIX -64 executable larger than 2GB
+ using MIPSpro 7.3.1.3 compilers. A couple .debug_pubnames
+ offsets were wrong.).
+*/
+int
+dwarf_get_section_max_offsets(Dwarf_Debug dbg,
+ Dwarf_Unsigned * debug_info_size,
+ Dwarf_Unsigned * debug_abbrev_size,
+ Dwarf_Unsigned * debug_line_size,
+ Dwarf_Unsigned * debug_loc_size,
+ Dwarf_Unsigned * debug_aranges_size,
+ Dwarf_Unsigned * debug_macinfo_size,
+ Dwarf_Unsigned * debug_pubnames_size,
+ Dwarf_Unsigned * debug_str_size,
+ Dwarf_Unsigned * debug_frame_size,
+ Dwarf_Unsigned * debug_ranges_size,
+ Dwarf_Unsigned * debug_typenames_size)
+{
+ *debug_info_size = dbg->de_debug_info.dss_size;
+ *debug_abbrev_size = dbg->de_debug_abbrev.dss_size;
+ *debug_line_size = dbg->de_debug_line.dss_size;
+ *debug_loc_size = dbg->de_debug_loc.dss_size;
+ *debug_aranges_size = dbg->de_debug_aranges.dss_size;
+ *debug_macinfo_size = dbg->de_debug_macinfo.dss_size;
+ *debug_pubnames_size = dbg->de_debug_pubnames.dss_size;
+ *debug_str_size = dbg->de_debug_str.dss_size;
+ *debug_frame_size = dbg->de_debug_frame.dss_size;
+ *debug_ranges_size = dbg->de_debug_ranges.dss_size;
+ *debug_typenames_size = dbg->de_debug_typenames.dss_size;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_leb.c b/usr/src/lib/libdwarf/common/dwarf_leb.c
new file mode 100644
index 0000000000..b3b5d262f5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_leb.c
@@ -0,0 +1,149 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+
+
+/*
+ decode ULEB
+*/
+Dwarf_Unsigned
+_dwarf_decode_u_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length)
+{
+ unsigned char byte;
+ Dwarf_Word word_number;
+ Dwarf_Unsigned number;
+ Dwarf_Sword shift;
+ Dwarf_Sword byte_length;
+
+ /* The following unrolls-the-loop for the first few bytes and
+ unpacks into 32 bits to make this as fast as possible.
+ word_number is assumed big enough that the shift has a defined
+ result. */
+ if ((*leb128 & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 1;
+ return (*leb128);
+ } else if ((*(leb128 + 1) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 2;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ return (word_number);
+ } else if ((*(leb128 + 2) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 3;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ word_number |= (*(leb128 + 2) & 0x7f) << 14;
+ return (word_number);
+ } else if ((*(leb128 + 3) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 4;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ word_number |= (*(leb128 + 2) & 0x7f) << 14;
+ word_number |= (*(leb128 + 3) & 0x7f) << 21;
+ return (word_number);
+ }
+
+ /* The rest handles long numbers Because the 'number' may be larger
+ than the default int/unsigned, we must cast the 'byte' before
+ the shift for the shift to have a defined result. */
+ number = 0;
+ shift = 0;
+ byte_length = 1;
+ byte = *(leb128);
+ for (;;) {
+ number |= ((Dwarf_Unsigned) (byte & 0x7f)) << shift;
+
+ if ((byte & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = byte_length;
+ return (number);
+ }
+ shift += 7;
+
+ byte_length++;
+ ++leb128;
+ byte = *leb128;
+ }
+}
+
+#define BITSINBYTE 8
+
+/*
+ decode SLEB
+*/
+Dwarf_Signed
+_dwarf_decode_s_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length)
+{
+ Dwarf_Signed number = 0;
+ Dwarf_Bool sign = 0;
+ Dwarf_Sword shift = 0;
+ unsigned char byte = *leb128;
+ Dwarf_Sword byte_length = 1;
+
+ /* byte_length being the number of bytes of data absorbed so far in
+ turning the leb into a Dwarf_Signed. */
+
+ for (;;) {
+ sign = byte & 0x40;
+ number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift;
+ shift += 7;
+
+ if ((byte & 0x80) == 0) {
+ break;
+ }
+ ++leb128;
+ byte = *leb128;
+ byte_length++;
+ }
+
+ if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) {
+ number |= -((Dwarf_Signed) 1 << shift);
+ }
+
+ if (leb128_length != NULL)
+ *leb128_length = byte_length;
+ return (number);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_line.c b/usr/src/lib/libdwarf/common/dwarf_line.c
new file mode 100644
index 0000000000..e7e15e7c1a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line.c
@@ -0,0 +1,1951 @@
+/*
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_line.h"
+
+static int
+is_path_separator(Dwarf_Small s)
+{
+ if(s == '/') {
+ return 1;
+ }
+#ifdef HAVE_WINDOWS_PATH
+ if(s == '\\') {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* Return 0 if false, 1 if true.
+ If HAVE_WINDOWS_PATH is defined we
+ attempt to handle windows full paths:
+ \\something or C:cwdpath.c
+*/
+static int
+file_name_is_full_path(Dwarf_Small *fname)
+{
+ Dwarf_Small firstc = *fname;
+ if(is_path_separator(firstc)) {
+ /* Full path. */
+ return 1;
+ }
+ if(!firstc) {
+ return 0;
+ }
+#ifdef HAVE_WINDOWS_PATH
+ if((firstc >= 'A' && firstc <= 'Z') ||
+ (firstc >= 'a' && firstc <= 'z')) {
+ Dwarf_Small secondc = fname[1];
+ if (secondc == ':') {
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/*
+ Although source files is supposed to return the
+ source files in the compilation-unit, it does
+ not look for any in the statement program. In
+ other words, it ignores those defined using the
+ extended opcode DW_LNE_define_file.
+*/
+int
+dwarf_srcfiles(Dwarf_Die die,
+ char ***srcfiles,
+ Dwarf_Signed * srcfilecount, Dwarf_Error * error)
+{
+ /* This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr;
+
+ /* Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = 0;
+
+ /* Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ /* This points to a block of char *'s, each of which points to a
+ file name. */
+ char **ret_files = 0;
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg = 0;
+
+ /* Used to chain the file names. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Half attrform = 0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ struct Line_Table_Prefix_s line_prefix;
+ int i = 0;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ /* Reset error. */
+ if (error != NULL)
+ *error = NULL;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ if (dbg->de_debug_line.dss_index == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ lres = dwarf_whatform(stmt_list_attr,&attrform,error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
+ attrform != DW_FORM_sec_offset ) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /*
+ If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+ dwarf_init_line_table_prefix(&line_prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ dbg->de_debug_line.dss_size,
+ &line_ptr_out,
+ &line_prefix,
+ NULL, NULL,error,
+ 0);
+
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ return dres;
+ }
+
+ line_ptr = line_ptr_out;
+ }
+
+ for (i = 0; i < line_prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *fe =
+ line_prefix.pf_line_table_file_entries + i;
+ char *file_name = (char *) fe->lte_filename;
+ char *dir_name = 0;
+ char *full_name = 0;
+ Dwarf_Unsigned dir_index = fe->lte_directory_index;
+
+ if (dir_index == 0) {
+ dir_name = (char *) comp_dir;
+ } else {
+ dir_name =
+ (char *) line_prefix.pf_include_directories[
+ fe->lte_directory_index - 1];
+ }
+
+ /* dir_name can be NULL if there is no DW_AT_comp_dir */
+ if(dir_name == 0 || file_name_is_full_path((unsigned char *)file_name)) {
+ /* This is safe because dwarf_dealloc is careful to not
+ dealloc strings which are part of the raw .debug_* data.
+ */
+ full_name = file_name;
+ } else {
+ full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ strlen(dir_name) + 1 +
+ strlen(file_name) +
+ 1);
+ if (full_name == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* This is not careful to avoid // in the output, Nothing
+ forces a 'canonical' name format here. Unclear if this
+ needs to be fixed. */
+ strcpy(full_name, dir_name);
+ strcat(full_name, "/");
+ strcat(full_name, file_name);
+ }
+ curr_chain =
+ (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = full_name;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+
+ curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+
+
+
+ if (line_prefix.pf_files_count == 0) {
+ *srcfiles = NULL;
+ *srcfilecount = 0;
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ ret_files = (char **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, line_prefix.pf_files_count);
+ if (ret_files == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < line_prefix.pf_files_count; i++) {
+ *(ret_files + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *srcfiles = ret_files;
+ *srcfilecount = line_prefix.pf_files_count;
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_OK);
+}
+
+
+/*
+ return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
+*/
+int
+_dwarf_internal_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * count,
+ Dwarf_Bool doaddrs,
+ Dwarf_Bool dolines, Dwarf_Error * error)
+{
+ /* This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr = 0;
+
+ /* This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /* Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr = 0;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr = 0;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = NULL;
+
+ /* Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ Dwarf_File_Entry file_entries = 0;
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word file = 1;
+ Dwarf_Word line = 1;
+ Dwarf_Word column = 0;
+
+ /* Phony init. See below for true initialization. */
+ Dwarf_Bool is_stmt = false;
+
+ Dwarf_Bool basic_block = false;
+ Dwarf_Bool prologue_end = false;
+ Dwarf_Bool epilogue_begin = false;
+ Dwarf_Small isa = 0;
+ Dwarf_Bool end_sequence = false;
+
+ /* These pointers are used to build the list of files names by this
+ cu. cur_file_entry points to the file name being added, and
+ prev_file_entry to the previous one. */
+ Dwarf_File_Entry cur_file_entry, prev_file_entry;
+
+ Dwarf_Sword i = 0;
+ Dwarf_Sword file_entry_count = 0;
+
+ /* This is the current opcode read from the statement program. */
+ Dwarf_Small opcode = 0;
+
+ /* Pointer to a Dwarf_Line_Context_s structure that contains the
+ context such as file names and include directories for the set
+ of lines being generated. */
+ Dwarf_Line_Context line_context = 0;
+
+ /* This is a pointer to the current line being added to the line
+ matrix. */
+ Dwarf_Line curr_line = 0;
+
+ /* These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Sword advance_line = 0;
+
+ /* This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc = 0;
+
+ /* Counts the number of lines in the line matrix. */
+ Dwarf_Sword line_count = 0;
+
+ /* This is the length of an extended opcode instr. */
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+ struct Line_Table_Prefix_s prefix;
+
+ /* Used to chain together pointers to line table entries that are
+ later used to create a block of Dwarf_Line entries. */
+ Dwarf_Chain chain_line = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Chain curr_chain = NULL;
+
+ /* This points to a block of Dwarf_Lines, a pointer to which is
+ returned in linebuf. */
+ Dwarf_Line *block_line = 0;
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg = 0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ Dwarf_Half address_size = 0;
+
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ if (error != NULL)
+ *error = NULL;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ address_size = _dwarf_get_address_size(dbg, die);
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /* If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+ dwarf_init_line_table_prefix(&prefix);
+
+ {
+ Dwarf_Small *newlinep = 0;
+ int res = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ dbg->de_debug_line.dss_size,
+ &newlinep,
+ &prefix,
+ NULL,NULL,
+ error,
+ 0);
+
+ if (res == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return res;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+ line_ptr = newlinep;
+ }
+
+
+ /* Set up context structure for this set of lines. */
+ line_context = (Dwarf_Line_Context)
+ _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
+ if (line_context == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Fill out a Dwarf_File_Entry list as we use that to implement the
+ define_file operation. */
+ file_entries = prev_file_entry = NULL;
+ for (i = 0; i < prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *pfxfile =
+ prefix.pf_line_table_file_entries + i;
+
+ cur_file_entry = (Dwarf_File_Entry)
+ _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+ if (cur_file_entry == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ cur_file_entry->fi_file_name = pfxfile->lte_filename;
+ cur_file_entry->fi_dir_index = pfxfile->lte_directory_index;
+ cur_file_entry->fi_time_last_mod =
+ pfxfile->lte_last_modification_time;
+
+ cur_file_entry->fi_file_length = pfxfile->lte_length_of_file;
+
+ if (file_entries == NULL)
+ file_entries = cur_file_entry;
+ else
+ prev_file_entry->fi_next = cur_file_entry;
+ prev_file_entry = cur_file_entry;
+
+ file_entry_count++;
+ }
+
+
+ /* Initialize the one state machine variable that depends on the
+ prefix. */
+ is_stmt = prefix.pf_default_is_stmt;
+
+
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type;
+
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+
+
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ ** Read and discard operands we don't
+ ** understand.
+ ** arbitrary choice of unsigned read.
+ ** signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ }
+ } else if (type == LOP_SPECIAL) {
+ /* This op code is a special op in the object, no matter
+ that it might fall into the standard op range in this
+ compile. That is, these are special opcodes between
+ opcode_base and MAX_LINE_OP_CODE. (including
+ opcode_base and MAX_LINE_OP_CODE) */
+
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ if (dolines) {
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
+ curr_line->li_addr_line.li_l_data.li_basic_block =
+ basic_block;
+ curr_line->li_addr_line.li_l_data.li_end_sequence =
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.li_prologue_end =
+ prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ curr_line->li_context = line_context;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ basic_block = false;
+ } else if (type == LOP_STANDARD) {
+ switch (opcode) {
+
+ case DW_LNS_copy:{
+ if (dolines) {
+
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg,
+ DW_DLA_LINE,
+ 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt =
+ is_stmt;
+ curr_line->li_addr_line.li_l_data.
+ li_basic_block = basic_block;
+ curr_line->li_addr_line.li_l_data.
+ li_end_sequence = end_sequence;
+ curr_line->li_context = line_context;
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.
+ li_prologue_end = prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ basic_block = false;
+ prologue_end = false;
+ epilogue_begin = false;
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ file = (Dwarf_Word) utmp2;
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ column = (Dwarf_Word) utmp2;
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+
+ is_stmt = !is_stmt;
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ basic_block = true;
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address = address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_prologue_end:{
+
+ prologue_end = true;
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ epilogue_begin = true;
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+ }
+
+ } else if (type == LOP_EXTENDED) {
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ /* Dwarf_Small is a ubyte and the extended opcode is a
+ ubyte, though not stated as clearly in the 2.0.0 spec as
+ one might hope. */
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ end_sequence = true;
+
+ if (dolines) {
+ curr_line = (Dwarf_Line)
+ _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt =
+ prefix.pf_default_is_stmt;
+ curr_line->li_addr_line.li_l_data.
+ li_basic_block = basic_block;
+ curr_line->li_addr_line.li_l_data.
+ li_end_sequence = end_sequence;
+ curr_line->li_context = line_context;
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.
+ li_prologue_end = prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = prefix.pf_default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+
+
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr, address_size);
+ if (doaddrs) {
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg,
+ DW_DLA_LINE,
+ 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_offset =
+ line_ptr - dbg->de_debug_line.dss_data;
+
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ line_ptr += address_size;
+ }
+
+ break;
+ }
+
+ case DW_LNE_define_file:{
+
+ if (dolines) {
+ cur_file_entry = (Dwarf_File_Entry)
+ _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+ if (cur_file_entry == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ cur_file_entry->fi_file_name =
+ (Dwarf_Small *) line_ptr;
+ line_ptr =
+ line_ptr + strlen((char *) line_ptr) + 1;
+
+ cur_file_entry->fi_dir_index = (Dwarf_Sword)
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ cur_file_entry->fi_time_last_mod =
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ cur_file_entry->fi_file_length =
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ if (file_entries == NULL)
+ file_entries = cur_file_entry;
+ else
+ prev_file_entry->fi_next = cur_file_entry;
+ prev_file_entry = cur_file_entry;
+
+ file_entry_count++;
+ }
+ break;
+ }
+
+ default:{
+ /* This is an extended op code we do not know about,
+ other than we know now many bytes it is
+ and the op code and the bytes of operand. */
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_EXT_OPCODE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr += remaining_bytes;
+ break;
+ }
+ }
+
+ }
+ }
+
+ block_line = (Dwarf_Line *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
+ if (block_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < line_count; i++) {
+ *(block_line + i) = curr_chain->ch_item;
+ head_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
+ }
+
+ line_context->lc_file_entries = file_entries;
+ line_context->lc_file_entry_count = file_entry_count;
+ line_context->lc_include_directories_count =
+ prefix.pf_include_directories_count;
+ if (prefix.pf_include_directories_count > 0) {
+ /* This gets a pointer to the *first* include dir. The others
+ follow directly with the standard DWARF2/3 NUL byte
+ following the last. */
+ line_context->lc_include_directories =
+ prefix.pf_include_directories[0];
+ }
+
+ line_context->lc_line_count = line_count;
+ line_context->lc_compilation_directory = comp_dir;
+ line_context->lc_version_number = prefix.pf_version;
+ line_context->lc_dbg = dbg;
+ *count = line_count;
+
+ *linebuf = block_line;
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
+
+int
+dwarf_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+ Dwarf_Signed count = 0;
+ int res = _dwarf_internal_srclines(die, linebuf, &count,
+ /* addrlist= */ false,
+ /* linelist= */ true, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ *linecount = count;
+ return res;
+}
+
+
+
+/* Every line table entry (except DW_DLE_end_sequence,
+ which is returned using dwarf_lineendsequence())
+ potentially has the begin-statement
+ flag marked 'on'. This returns thru *return_bool,
+ the begin-statement flag.
+*/
+
+int
+dwarf_linebeginstatement(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL || return_bool == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (line->li_addr_line.li_l_data.li_is_stmt);
+ return DW_DLV_OK;
+}
+
+/* At the end of any contiguous line-table there may be
+ a DW_LNE_end_sequence operator.
+ This returns non-zero thru *return_bool
+ if and only if this 'line' entry was a DW_LNE_end_sequence.
+
+ Within a compilation unit or function there may be multiple
+ line tables, each ending with a DW_LNE_end_sequence.
+ Each table describes a contiguous region.
+ Because compilers may split function code up in arbitrary ways
+ compilers may need to emit multiple contigous regions (ie
+ line tables) for a single function.
+ See the DWARF3 spec section 6.2.
+*/
+int
+dwarf_lineendsequence(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (line->li_addr_line.li_l_data.li_end_sequence);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-number.
+ If the entry is a DW_LNE_end_sequence the line-number is
+ meaningless (see dwarf_lineendsequence(), just above).
+*/
+int
+dwarf_lineno(Dwarf_Line line,
+ Dwarf_Unsigned * ret_lineno, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineno == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineno = (line->li_addr_line.li_l_data.li_line);
+ return DW_DLV_OK;
+}
+
+/* Each 'line' entry has a file-number, and index into the file table.
+ If the entry is a DW_LNE_end_sequence the index is
+ meaningless (see dwarf_lineendsequence(), just above).
+ The file number returned is an index into the file table
+ produced by dwarf_srcfiles(), but care is required: the
+ li_file begins with 1 for real files, so that the li_file returned here
+ is 1 greater than its index into the dwarf_srcfiles() output array.
+ And entries from DW_LNE_define_file don't appear in
+ the dwarf_srcfiles() output so file indexes from here may exceed
+ the size of the dwarf_srcfiles() output array size.
+*/
+int
+dwarf_line_srcfileno(Dwarf_Line line,
+ Dwarf_Unsigned * ret_fileno, Dwarf_Error * error)
+{
+ if (line == NULL || ret_fileno == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /* li_file must be <= line->li_context->lc_file_entry_count else it
+ is trash. li_file 0 means not attributable to any source file
+ per dwarf2/3 spec. */
+
+ *ret_fileno = (line->li_addr_line.li_l_data.li_file);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-address.
+ If the entry is a DW_LNE_end_sequence the adddress
+ is one-beyond the last address this contigous region
+ covers, so the address is not inside the region,
+ but is just outside it.
+*/
+int
+dwarf_lineaddr(Dwarf_Line line,
+ Dwarf_Addr * ret_lineaddr, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineaddr == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineaddr = (line->li_address);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a column-within-line (offset
+ within the line) where the
+ source text begins.
+ If the entry is a DW_LNE_end_sequence the line-number is
+ meaningless (see dwarf_lineendsequence(), just above).
+ Lines of text begin at column 1. The value 0
+ means the line begins at the left edge of the line.
+ (See the DWARF3 spec, section 6.2.2).
+*/
+int
+dwarf_lineoff(Dwarf_Line line,
+ Dwarf_Signed * ret_lineoff, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineoff == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineoff =
+ (line->li_addr_line.li_l_data.li_column ==
+ 0 ? -1 : line->li_addr_line.li_l_data.li_column);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error)
+{
+ Dwarf_Signed i = 0;
+ Dwarf_File_Entry file_entry;
+ Dwarf_Small *name_buffer = 0;
+ Dwarf_Small *include_directories = 0;
+ Dwarf_Small include_direc_full_path = 0;
+ Dwarf_Small file_name_full_path = 0;
+ Dwarf_Debug dbg = 0;
+ unsigned int comp_dir_len = 0;
+
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (line->li_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = line->li_context->lc_dbg;
+
+ if (line->li_addr_line.li_l_data.li_file >
+ line->li_context->lc_file_entry_count) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ if (line->li_addr_line.li_l_data.li_file == 0) {
+ /* No file name known: see dwarf2/3 spec. */
+ _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+ return (DW_DLV_ERROR);
+ }
+ file_entry = line->li_context->lc_file_entries;
+ /* ASSERT: li_file > 0, dwarf correctness issue, see line table
+ definition of dwarf2/3 spec. */
+ /* Example: if li_file is 2 and lc_file_entry_count is 3,
+ file_entry is file 3 (1 based), aka 2( 0 based) file_entry->next
+ is file 2 (1 based), aka 1( 0 based) file_entry->next->next is
+ file 1 (1 based), aka 0( 0 based) file_entry->next->next->next
+ is NULL.
+
+ and this loop finds the file_entry we need (2 (1 based) in this
+ case). Because lc_file_entries are in reverse order and
+ effectively zero based as a count whereas li_file is 1 based. */
+ for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--)
+ file_entry = file_entry->fi_next;
+
+ if (file_entry->fi_file_name == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+ return (DW_DLV_ERROR);
+ }
+
+ file_name_full_path = file_name_is_full_path(file_entry->fi_file_name);
+ if (file_name_full_path) {
+ *ret_linesrc = ((char *) file_entry->fi_file_name);
+ return DW_DLV_OK;
+ }
+
+ if (file_entry->fi_dir_index == 0) {
+
+ /* dir_index of 0 means that the compilation was in the
+ 'current directory of compilation' */
+ if (line->li_context->lc_compilation_directory == NULL) {
+ /* we don't actually *have* a current directory of
+ compilation: DW_AT_comp_dir was not present Rather than
+ emitting DW_DLE_NO_COMP_DIR lets just make an empty name
+ here. In other words, do the best we can with what we do
+ have instead of reporting an error. _dwarf_error(dbg,
+ error, DW_DLE_NO_COMP_DIR); return(DW_DLV_ERROR); */
+ comp_dir_len = 0;
+ } else {
+ comp_dir_len = strlen((char *)
+ (line->li_context->
+ lc_compilation_directory));
+ }
+
+ name_buffer =
+ _dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING,
+ comp_dir_len + 1 +
+ strlen((char *) file_entry->fi_file_name) +
+ 1);
+ if (name_buffer == NULL) {
+ _dwarf_error(line->li_context->lc_dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (comp_dir_len > 0) {
+ /* if comp_dir_len is 0 we do not want to put a / in front
+ of the fi_file_name as we just don't know anything. */
+ strcpy((char *) name_buffer,
+ (char *) (line->li_context->
+ lc_compilation_directory));
+ strcat((char *) name_buffer, "/");
+ }
+ strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+ *ret_linesrc = ((char *) name_buffer);
+ return DW_DLV_OK;
+ }
+
+ if (file_entry->fi_dir_index >
+ line->li_context->lc_include_directories_count) {
+ _dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ include_directories = line->li_context->lc_include_directories;
+ for (i = file_entry->fi_dir_index - 1; i > 0; i--)
+ include_directories += strlen((char *) include_directories) + 1;
+
+ if (line->li_context->lc_compilation_directory) {
+ comp_dir_len = strlen((char *)
+ (line->li_context->lc_compilation_directory));
+ } else {
+ /* No DW_AT_comp_dir present. Do the best we can without it. */
+ comp_dir_len = 0;
+ }
+
+ include_direc_full_path = file_name_is_full_path(include_directories);
+ name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ (include_direc_full_path ? 0 : comp_dir_len + 1) +
+ strlen((char *)include_directories) + 1 +
+ strlen((char *)file_entry->fi_file_name) + 1);
+ if (name_buffer == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (!include_direc_full_path) {
+ if (comp_dir_len > 0) {
+ strcpy((char *)name_buffer,
+ (char *)line->li_context->lc_compilation_directory);
+ /* Who provides the / needed after the compilation
+ directory? */
+ if (!is_path_separator(name_buffer[comp_dir_len - 1])) {
+ /* Here we provide the / separator. It
+ should work ok for Windows */
+ /* Overwrite previous nul terminator with needed / */
+ name_buffer[comp_dir_len] = '/';
+ name_buffer[comp_dir_len + 1] = 0;
+ }
+ }
+ } else {
+ strcpy((char *) name_buffer, "");
+ }
+ strcat((char *) name_buffer, (char *) include_directories);
+ strcat((char *) name_buffer, "/");
+ strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+ *ret_linesrc = ((char *) name_buffer);
+ return DW_DLV_OK;
+}
+
+/* Every line table entry potentially has the basic-block-start
+ flag marked 'on'. This returns thru *return_bool,
+ the basic-block-start flag.
+*/
+int
+dwarf_lineblock(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *return_bool = (line->li_addr_line.li_l_data.li_basic_block);
+ return DW_DLV_OK;
+}
+
+
+#if 0 /* Ignore this. This needs major
+ re-work. */
+/*
+ This routine works by looking for exact matches between
+ the current line address and pc, and crossovers from
+ from less than pc value to greater than. At each line
+ that satisfies the above, it records a pointer to the
+ line, and the difference between the address and pc.
+ It then scans these pointers and picks out those with
+ the smallest difference between pc and address.
+*/
+int
+dwarf_pclines(Dwarf_Debug dbg,
+ Dwarf_Addr pc,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed slide,
+ Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+ /*
+ Scans the line matrix for the current cu to which a pointer
+ exists in dbg. */
+ Dwarf_Line line;
+ Dwarf_Line prev_line;
+
+ /*
+ These flags are for efficiency reasons. Check_line is true
+ initially, but set false when the address of the current line is
+ greater than pc. It is set true only when the address of the
+ current line falls below pc. This assumes that addresses within
+ the same segment increase, and we are only interested in the
+ switch from a less than pc address to a greater than. First_line
+ is set true initially, but set false after the first line is
+ scanned. This is to prevent looking at the address of previous
+ line when slide is DW_DLS_BACKWARD, and the first line is being
+ scanned. */
+ Dwarf_Bool check_line, first_line;
+
+ /*
+ Diff tracks the smallest difference a line address and the input
+ pc value. */
+ Dwarf_Signed diff, i;
+
+ /*
+ For the slide = DW_DLS_BACKWARD case, pc_less is the value of
+ the address of the line immediately preceding the first line
+ that has value greater than pc. For the slide = DW_DLS_FORWARD
+ case, pc_more is the values of address for the first line that
+ is greater than pc. Diff is the difference between either of the
+ these values and pc. */
+ Dwarf_Addr pc_less, pc_more;
+
+ /*
+ Pc_line_buf points to a chain of pointers to lines of which
+ those with a diff equal to the smallest difference will be
+ returned. */
+ Dwarf_Line *pc_line_buf, *pc_line;
+
+ /*
+ Chain_count counts the number of lines in the above chain for
+ which the diff is equal to the smallest difference This is the
+ number returned by this routine. */
+ Dwarf_Signed chain_count;
+
+ chain_head = NULL;
+
+ check_line = true;
+ first_line = true;
+ diff = MAX_LINE_DIFF;
+
+ for (i = 0; i < dbg->de_cu_line_count; i++) {
+
+ line = *(dbg->de_cu_line_ptr + i);
+ prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1);
+
+ if (line->li_address == pc) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = line;
+ chain_ptr->diff = diff = 0;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ } else
+ /*
+ Look for crossover from less than pc address to greater
+ than. */
+ if (check_line && line->li_address > pc &&
+ (first_line ? 0 : prev_line->li_address) < pc)
+
+ if (slide == DW_DLS_BACKWARD && !first_line) {
+ pc_less = prev_line->li_address;
+ if (pc - pc_less <= diff) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = prev_line;
+ chain_ptr->diff = diff = pc - pc_less;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ }
+ check_line = false;
+ } else if (slide == DW_DLS_FORWARD) {
+ pc_more = line->li_address;
+ if (pc_more - pc <= diff) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = line;
+ chain_ptr->diff = diff = pc_more - pc;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ }
+ check_line = false;
+ } else
+ /* Check addresses only when they go */
+ /* below pc. */
+ if (line->li_address < pc)
+ check_line = true;
+
+ first_line = false;
+ }
+
+ chain_count = 0;
+ for (chain_ptr = chain_head; chain_ptr != NULL;
+ chain_ptr = chain_ptr->next)
+ if (chain_ptr->diff == diff)
+ chain_count++;
+
+ pc_line_buf = pc_line = (Dwarf_Line)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count);
+ for (chain_ptr = chain_head; chain_ptr != NULL;
+ chain_ptr = chain_ptr->next)
+ if (chain_ptr->diff == diff) {
+ *pc_line = chain_ptr->line;
+ pc_line++;
+ }
+
+ for (chain_ptr = chain_head; chain_ptr != NULL;) {
+ chain_head = chain_ptr;
+ chain_ptr = chain_ptr->next;
+ dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN);
+ }
+
+ *linebuf = pc_line_buf;
+ return (chain_count);
+}
+#endif
+
+
+
+/*
+ It's impossible for callers of dwarf_srclines() to get to and
+ free all the resources (in particular, the li_context and its
+ lc_file_entries).
+ So this function, new July 2005, does it.
+*/
+
+void
+dwarf_srclines_dealloc(Dwarf_Debug dbg, Dwarf_Line * linebuf,
+ Dwarf_Signed count)
+{
+
+ Dwarf_Signed i = 0;
+ struct Dwarf_Line_Context_s *context = 0;
+
+ if (count > 0) {
+ /* All these entries share a single context */
+ context = linebuf[0]->li_context;
+ }
+ for (i = 0; i < count; ++i) {
+ dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE);
+ }
+ dwarf_dealloc(dbg, linebuf, DW_DLA_LIST);
+
+ if (context) {
+ Dwarf_File_Entry fe = context->lc_file_entries;
+
+ while (fe) {
+ Dwarf_File_Entry fenext = fe->fi_next;
+
+ dwarf_dealloc(dbg, fe, DW_DLA_FILE_ENTRY);
+ fe = fenext;
+ }
+ dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT);
+ }
+
+ return;
+}
+
+/* Operand counts per standard operand.
+ The initial zero is for DW_LNS_copy.
+ This is an economical way to verify we understand the table
+ of standard-opcode-lengths in the line table prologue. */
+#define STANDARD_OPERAND_COUNT_DWARF2 9
+#define STANDARD_OPERAND_COUNT_DWARF3 12
+static unsigned char
+ dwarf_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
+ /* DWARF2 */
+ 0,
+ 1, 1, 1, 1,
+ 0, 0, 0,
+ 1,
+ /* Following are new for DWARF3. */
+ 0, 0, 1
+};
+
+/* We have a normal standard opcode base, but
+ an arm compiler emitted a non-standard table!
+ This could lead to problems...
+ ARM C/C++ Compiler, RVCT4.0 [Build 4
+ 00] seems to get the table wrong . */
+static unsigned char
+dwarf_arm_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
+ /* DWARF2 */
+ 0,
+ 1, 1, 1, 1,
+ 0, 0, 0,
+ 0, /* <<< --- this is wrong */
+ /* Following are new for DWARF3. */
+ 0, 0, 1
+};
+
+static void
+print_header_issue(Dwarf_Debug dbg,
+ char *specific_msg,
+ Dwarf_Small *data_start,
+ int *err_count_out)
+{
+ if(!err_count_out)
+ return;
+ printf("*** DWARF CHECK: "
+ "line table header: %s",
+ specific_msg);
+ if( data_start >= dbg->de_debug_line.dss_data &&
+ (data_start < (dbg->de_debug_line.dss_data +
+ dbg->de_debug_line.dss_size))) {
+ Dwarf_Unsigned off = data_start - dbg->de_debug_line.dss_data;
+ printf(" at .debug_line section offset 0x%" DW_PR_DUx
+ " ( %" DW_PR_DUu " ) ",
+ off,off);
+ } else {
+ printf(" (unknown section location) ");
+ }
+ printf("***\n");
+ *err_count_out += 1;
+}
+
+
+
+/* Common line table prefix reading code.
+ Returns DW_DLV_OK, DW_DLV_ERROR.
+ DW_DLV_NO_ENTRY cannot be returned, but callers should
+ assume it is possible.
+
+ The prefix_out area must be initialized properly before calling this.
+
+ Has the side effect of allocating arrays which
+ must be freed (see the Line_Table_Prefix_s struct which
+ holds the pointers to space we allocate here).
+
+ bogus_bytes_ptr and bogus_bytes are output values which
+ let a print-program notify the user of some surprising bytes
+ after a line table header and before the line table instructions.
+ These can be ignored unless one is printing.
+ And are ignored if NULL passed as the pointer.
+*/
+
+/* err_count_out may be NULL, in which case we
+ make no attempt to count checking-type errors.
+ Checking-type errors do not stop us, we just report them.
+*/
+int
+dwarf_read_line_table_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * data_start,
+ Dwarf_Unsigned data_length,
+ Dwarf_Small ** updated_data_start_out,
+ struct Line_Table_Prefix_s *prefix_out,
+ Dwarf_Small ** bogus_bytes_ptr,
+ Dwarf_Unsigned *bogus_bytes,
+ Dwarf_Error * err,
+ int *err_count_out)
+{
+ Dwarf_Small *line_ptr = data_start;
+ Dwarf_Unsigned total_length = 0;
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Unsigned prologue_length = 0;
+ Dwarf_Half version = 0;
+ Dwarf_Unsigned directories_count = 0;
+ Dwarf_Unsigned directories_malloc = 0;
+ Dwarf_Unsigned files_count = 0;
+ Dwarf_Unsigned files_malloc = 0;
+ Dwarf_Small *line_ptr_end = 0;
+ Dwarf_Small *lp_begin = 0;
+ if(bogus_bytes_ptr) *bogus_bytes_ptr = 0;
+ if(bogus_bytes) *bogus_bytes= 0;
+
+ prefix_out->pf_line_ptr_start = line_ptr;
+ /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
+ line_ptr, local_length_size, local_extension_size);
+
+
+ line_ptr_end = line_ptr + total_length;
+ prefix_out->pf_line_ptr_end = line_ptr_end;
+ prefix_out->pf_length_field_length = local_length_size +
+ local_extension_size;
+ /* ASSERT: prefix_out->pf_length_field_length == line_ptr
+ -prefix_out->pf_line_ptr_start; */
+ if (line_ptr_end > dbg->de_debug_line.dss_data +
+ dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (line_ptr_end > data_start + data_length) {
+ _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ prefix_out->pf_total_length = total_length;
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ prefix_out->pf_version = version;
+ line_ptr += sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP &&
+ version != CURRENT_VERSION_STAMP3) {
+ _dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
+ line_ptr, local_length_size);
+ prefix_out->pf_prologue_length = prologue_length;
+ line_ptr += local_length_size;
+ prefix_out->pf_line_prologue_start = line_ptr;
+
+ prefix_out->pf_minimum_instruction_length =
+ *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_default_is_stmt = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_line_base = *(signed char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Sbyte);
+
+ prefix_out->pf_line_range = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_opcode_base = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ /* Set up the array of standard opcode lengths. */
+ /* We think this works ok even for cross-endian processing of
+ objects. It might be wrong, we might need to specially process
+ the array of ubyte into host order. */
+ prefix_out->pf_opcode_length_table = line_ptr;
+
+ /* pf_opcode_base is one greater than the size of the array. */
+ line_ptr += prefix_out->pf_opcode_base - 1;
+
+ {
+ /* Determine (as best we can) whether the
+ pf_opcode_length_table holds 9 or 12 standard-conforming
+ entries. gcc4 upped to DWARF3's 12 without updating the
+ version number. */
+ int operand_ck_fail = true;
+
+ if (prefix_out->pf_opcode_base >= STANDARD_OPERAND_COUNT_DWARF3) {
+ int mismatch = memcmp(dwarf_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF3);
+ if(mismatch) {
+ if(err_count_out) {
+ print_header_issue(dbg,"standard-operands did not match",
+ data_start,err_count_out);
+ }
+ mismatch = memcmp(dwarf_arm_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF3);
+ if(!mismatch && err_count_out) {
+ print_header_issue(dbg,"arm (incorrect) operands in use",
+ data_start,err_count_out);
+ }
+ }
+ if (!mismatch) {
+ if (version == 2) {
+ if(err_count_out) {
+ print_header_issue(dbg,
+ "standard DWARF3 operands matched, but is DWARF2 linetable",
+ data_start,err_count_out);
+ }
+ }
+ operand_ck_fail = false;
+ prefix_out->pf_std_op_count =
+ STANDARD_OPERAND_COUNT_DWARF3;
+ }
+ }
+ if (operand_ck_fail) {
+ if (prefix_out->pf_opcode_base >=
+ STANDARD_OPERAND_COUNT_DWARF2) {
+
+ int mismatch =
+ memcmp(dwarf_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF2);
+ if(mismatch) {
+ if(err_count_out) {
+ print_header_issue(dbg,"standard-operands-lengths did not match",
+ data_start,err_count_out);
+ }
+ mismatch = memcmp(dwarf_arm_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF2);
+ if(!mismatch && err_count_out) {
+ print_header_issue(dbg,"arm (incorrect) operand in use",
+ data_start,err_count_out);
+ }
+ }
+
+ if (!mismatch) {
+ operand_ck_fail = false;
+ prefix_out->pf_std_op_count =
+ STANDARD_OPERAND_COUNT_DWARF2;
+ }
+ }
+ }
+ if (operand_ck_fail) {
+ /* Here we are not sure what the pf_std_op_count is. */
+ _dwarf_error(dbg, err, DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ /* At this point we no longer need to check operand counts. */
+
+
+ directories_count = 0;
+ directories_malloc = 5;
+ prefix_out->pf_include_directories = malloc(sizeof(Dwarf_Small *) *
+ directories_malloc);
+ if (prefix_out->pf_include_directories == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(prefix_out->pf_include_directories, 0,
+ sizeof(Dwarf_Small *) * directories_malloc);
+
+ while ((*(char *) line_ptr) != '\0') {
+ if (directories_count >= directories_malloc) {
+ Dwarf_Unsigned expand = 2 * directories_malloc;
+ Dwarf_Unsigned bytesalloc = sizeof(Dwarf_Small *) * expand;
+ Dwarf_Small **newdirs =
+ realloc(prefix_out->pf_include_directories,
+ bytesalloc);
+
+ if (!newdirs) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ /* Doubled size, zero out second half. */
+ memset(newdirs + directories_malloc, 0,
+ sizeof(Dwarf_Small *) * directories_malloc);
+ directories_malloc = expand;
+ prefix_out->pf_include_directories = newdirs;
+ }
+ prefix_out->pf_include_directories[directories_count] =
+ line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+ directories_count++;
+ }
+ prefix_out->pf_include_directories_count = directories_count;
+ line_ptr++;
+
+ files_count = 0;
+ files_malloc = 5;
+ prefix_out->pf_line_table_file_entries =
+ malloc(sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+ if (prefix_out->pf_line_table_file_entries == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(prefix_out->pf_line_table_file_entries, 0,
+ sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+
+ while (*(char *) line_ptr != '\0') {
+ Dwarf_Unsigned utmp;
+ Dwarf_Unsigned dir_index = 0;
+ Dwarf_Unsigned lastmod = 0;
+ Dwarf_Unsigned file_length = 0;
+ struct Line_Table_File_Entry_s *curline;
+ Dwarf_Word leb128_length = 0;
+
+
+ if (files_count >= files_malloc) {
+ Dwarf_Unsigned expand = 2 * files_malloc;
+ struct Line_Table_File_Entry_s *newfiles =
+ realloc(prefix_out->pf_line_table_file_entries,
+ sizeof(struct Line_Table_File_Entry_s) *
+ expand);
+ if (!newfiles) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(newfiles + files_malloc, 0,
+ sizeof(struct Line_Table_File_Entry_s) *
+ files_malloc);
+ files_malloc = expand;
+ prefix_out->pf_line_table_file_entries = newfiles;
+ }
+ curline = prefix_out->pf_line_table_file_entries + files_count;
+
+ curline->lte_filename = line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp);
+ dir_index = (Dwarf_Sword) utmp;
+ if (dir_index > directories_count) {
+ _dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD);
+ return (DW_DLV_ERROR);
+ }
+ curline->lte_directory_index = dir_index;
+
+ lastmod = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+ curline->lte_last_modification_time = lastmod;
+
+ /* Skip over file length. */
+ file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+ curline->lte_length_of_file = file_length;
+
+ ++files_count;
+
+ }
+ prefix_out->pf_files_count = files_count;
+ /* Skip trailing nul byte */
+ ++line_ptr;
+
+
+ lp_begin = prefix_out->pf_line_prologue_start +
+ prefix_out->pf_prologue_length;
+ if (line_ptr != lp_begin) {
+ if(line_ptr > lp_begin) {
+ _dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ } else {
+ /* Bug in compiler. These
+ * bytes are really part of the instruction
+ * stream. The prefix_out->pf_prologue_length is
+ * wrong (12 too high). */
+ if(bogus_bytes_ptr) {
+ *bogus_bytes_ptr = line_ptr;
+ }
+ if(bogus_bytes) {
+ /* How far off things are. We expect the
+ value 12 ! */
+ *bogus_bytes = (lp_begin - line_ptr);
+ }
+ }
+ /* Ignore the lp_begin calc. Assume line_ptr right.
+ Making up for compiler bug. */
+ lp_begin = line_ptr;
+
+ }
+
+ *updated_data_start_out = lp_begin;
+ return DW_DLV_OK;
+}
+
+
+/* Initialize the Line_Table_Prefix_s struct.
+ memset is not guaranteed a portable initializer, but works
+ fine for current architectures. AFAIK.
+*/
+void
+dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+ memset(pf, 0, sizeof(*pf));
+}
+
+/* Free any malloc'd area. of the Line_Table_Prefix_s struct. */
+void
+dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+ if (pf->pf_include_directories) {
+ free(pf->pf_include_directories);
+ pf->pf_include_directories = 0;
+ }
+ if (pf->pf_line_table_file_entries) {
+ free(pf->pf_line_table_file_entries);
+ pf->pf_line_table_file_entries = 0;
+ }
+ return;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_line.h b/usr/src/lib/libdwarf/common/dwarf_line.h
new file mode 100644
index 0000000000..66d6062754
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line.h
@@ -0,0 +1,331 @@
+/*
+
+ Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#define DW_EXTENDED_OPCODE 0
+
+/*
+ This is used as the starting value for an algorithm
+ to get the minimum difference between 2 values.
+ UINT_MAX is used as our approximation to infinity.
+*/
+#define MAX_LINE_DIFF UINT_MAX
+
+/* This is for a sanity check on line
+ table extended opcodes.
+ It is entirely arbitrary, and 100 is surely too small if
+ someone was inserting strings in the opcode. */
+#define DW_LNE_LEN_MAX 100
+
+
+/*
+ This structure is used to build a list of all the
+ files that are used in the current compilation unit.
+ All of the fields execpt fi_next have meanings that
+ are obvious from section 6.2.4 of the Libdwarf Doc.
+*/
+struct Dwarf_File_Entry_s {
+ /* Points to string naming the file. */
+ Dwarf_Small *fi_file_name;
+
+ /*
+ Index into the list of directories of the directory in which
+ this file exits. */
+ Dwarf_Sword fi_dir_index;
+
+ /* Time of last modification of the file. */
+ Dwarf_Unsigned fi_time_last_mod;
+
+ /* Length in bytes of the file. */
+ Dwarf_Unsigned fi_file_length;
+
+ /* Pointer for chaining file entries. */
+ Dwarf_File_Entry fi_next;
+};
+
+
+typedef struct Dwarf_Line_Context_s *Dwarf_Line_Context;
+
+/*
+ This structure provides the context in which the fields of
+ a Dwarf_Line structure are interpreted. They come from the
+ statement program prologue. **Updated by dwarf_srclines in
+ dwarf_line.c.
+*/
+struct Dwarf_Line_Context_s {
+ /*
+ Points to a chain of entries providing info about source files
+ for the current set of Dwarf_Line structures. File number
+ 'li_file 1' is last on the list, the first list entry is the
+ file numbered lc_file_entry_count. The numbering of the file
+ names matches the dwarf2/3 line table specification file table
+ and DW_LNE_define_file numbering rules. */
+ Dwarf_File_Entry lc_file_entries;
+ /*
+ Count of number of source files for this set of Dwarf_Line
+ structures. */
+ Dwarf_Sword lc_file_entry_count;
+ /*
+ Points to the portion of .debug_line section that contains a
+ list of strings naming the included directories. */
+ Dwarf_Small *lc_include_directories;
+
+ /* Count of the number of included directories. */
+ Dwarf_Sword lc_include_directories_count;
+
+ /* Count of the number of lines for this cu. */
+ Dwarf_Sword lc_line_count;
+
+ /* Points to name of compilation directory. */
+ Dwarf_Small *lc_compilation_directory;
+
+ Dwarf_Debug lc_dbg;
+
+ Dwarf_Half lc_version_number; /* DWARF2/3 version number, 2
+ for DWARF2, 3 for DWARF3. */
+};
+
+
+/*
+ This structure defines a row of the line table.
+ All of the fields except li_offset have the exact
+ same meaning that is defined in Section 6.2.2
+ of the Libdwarf Document.
+
+ li_offset is used by _dwarf_addr_finder() which is called
+ by rqs(1), an sgi utility for 'moving' shared libraries
+ as if the static linker (ld) had linked the shared library
+ at the newly-specified address. Most libdwarf-using
+ apps will ignore li_offset and _dwarf_addr_finder().
+
+*/
+struct Dwarf_Line_s {
+ Dwarf_Addr li_address; /* pc value of machine instr */
+ union addr_or_line_s {
+ struct li_inner_s {
+ Dwarf_Sword li_file; /* int identifying src file */
+ /* li_file is a number 1-N, indexing into a conceptual
+ source file table as described in dwarf2/3 spec line
+ table doc. (see Dwarf_File_Entry lc_file_entries; and
+ Dwarf_Sword lc_file_entry_count;) */
+
+ Dwarf_Sword li_line; /* source file line number. */
+ Dwarf_Half li_column; /* source file column number */
+ Dwarf_Small li_isa;
+
+ /* To save space, use bit flags. */
+ /* indicate start of stmt */
+ unsigned char li_is_stmt:1;
+
+ /* indicate start basic block */
+ unsigned char li_basic_block:1;
+
+ /* first post sequence instr */
+ unsigned char li_end_sequence:1;
+
+ unsigned char li_prologue_end:1;
+ unsigned char li_epilogue_begin:1;
+ } li_l_data;
+ Dwarf_Off li_offset; /* for rqs */
+ } li_addr_line;
+ Dwarf_Line_Context li_context; /* assoc Dwarf_Line_Context_s */
+};
+
+
+int _dwarf_line_address_offsets(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offs,
+ Dwarf_Unsigned * returncount,
+ Dwarf_Error * err);
+int _dwarf_internal_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * count,
+ Dwarf_Bool doaddrs,
+ Dwarf_Bool dolines, Dwarf_Error * error);
+
+
+
+/* The LOP, WHAT_IS_OPCODE stuff is here so it can
+ be reused in 3 places. Seemed hard to keep
+ the 3 places the same without an inline func or
+ a macro.
+
+ Handling the line section where the header and the
+ file being processed do not match (unusual, but
+ planned for in the design of .debug_line)
+ is too tricky to recode this several times and keep
+ it right.
+
+ As it is the code starting up line-reading is duplicated
+ and that is just wrong to do. FIXME!
+*/
+#define LOP_EXTENDED 1
+#define LOP_DISCARD 2
+#define LOP_STANDARD 3
+#define LOP_SPECIAL 4
+
+#define WHAT_IS_OPCODE(type,opcode,base,opcode_length,line_ptr,highest_std) \
+ if( (opcode) < (base) ) { \
+ /* we know we must treat as a standard op \
+ or a special case. \
+ */ \
+ if((opcode) == DW_EXTENDED_OPCODE) { \
+ type = LOP_EXTENDED; \
+ } else if( ((highest_std)+1) >= (base)) { \
+ /* == Standard case: compile of \
+ dwarf_line.c and object \
+ have same standard op codes set. \
+ \
+ > Special case: compile of dwarf_line.c\
+ has things in standard op codes list \
+ in dwarf.h header not \
+ in the object: handle this as a standard\
+ op code in switch below. \
+ The header special ops overlap the \
+ object standard ops. \
+ The new standard op codes will not \
+ appear in the object. \
+ */ \
+ type = LOP_STANDARD; \
+ } else { \
+ /* These are standard opcodes in the object\
+ ** that were not defined in the header \
+ ** at the time dwarf_line.c \
+ ** was compiled. Provides the ability of \
+ ** out-of-date dwarf reader to read newer \
+ ** line table data transparently. \
+ */ \
+ type = LOP_DISCARD; \
+ } \
+ \
+ } else { \
+ /* Is a special op code. \
+ */ \
+ type = LOP_SPECIAL; \
+ }
+
+/* The following is from the dwarf definition of 'ubyte'
+ and is specifically mentioned in section 6.2.5.1, page 54
+ of the Rev 2.0.0 dwarf specification.
+*/
+
+#define MAX_LINE_OP_CODE 255
+
+
+/* The following structs (Line_Table_File_Entry_s,Line_Table_Prefix_s)
+ and functions allow refactoring common code into a single
+ reader routine.
+*/
+/* There can be zero of more of these needed for 1 line prologue. */
+struct Line_Table_File_Entry_s {
+ Dwarf_Small *lte_filename;
+ Dwarf_Unsigned lte_directory_index;
+ Dwarf_Unsigned lte_last_modification_time;
+ Dwarf_Unsigned lte_length_of_file;
+};
+
+/* Data picked up from the line table prologue for a single
+CU. */
+struct Line_Table_Prefix_s {
+
+ /* pf_total_length is the value of the length field for the line
+ table of this CU. So it does not count the length of itself (the
+ length value) for consistency with the say lenghts recorded in
+ DWARF2/3. */
+ Dwarf_Unsigned pf_total_length;
+
+ /* Length of the initial length field itself. */
+ Dwarf_Half pf_length_field_length;
+
+ /* The version is 2 for DWARF2, 3 for DWARF3 */
+ Dwarf_Half pf_version;
+
+ Dwarf_Unsigned pf_prologue_length;
+ Dwarf_Small pf_minimum_instruction_length;
+
+ /* Start and end of this CU line area. pf_line_ptr_start +
+ pf_total_length + pf_length_field_length == pf_line_ptr_end.
+ Meaning pf_line_ptr_start is before the length info. */
+ Dwarf_Small *pf_line_ptr_start;
+ Dwarf_Small *pf_line_ptr_end;
+
+ /* Used to check that decoding of the line prologue is done right. */
+ Dwarf_Small *pf_line_prologue_start;
+
+ Dwarf_Small pf_default_is_stmt;
+ Dwarf_Sbyte pf_line_base;
+ Dwarf_Small pf_line_range;
+
+ /* Highest std opcode (+1). */
+ Dwarf_Small pf_opcode_base;
+
+ /* pf_opcode_base -1 entries (each a count, normally the value of
+ each entry is 0 or 1). */
+ Dwarf_Small *pf_opcode_length_table;
+
+ Dwarf_Unsigned pf_include_directories_count;
+ /* Array of pointers to dir strings. pf_include_directories_count
+ entriesin the array. */
+ Dwarf_Small **pf_include_directories;
+
+ /* Count of entries in line_table_file_entries array. */
+ Dwarf_Unsigned pf_files_count;
+ struct Line_Table_File_Entry_s *pf_line_table_file_entries;
+
+ /* The number to treat as standard ops. This is a special
+ accomodation of gcc using the new standard opcodes but not
+ updating the version number. It's legal dwarf2, but much better
+ for the user to understand as dwarf3 when 'it looks ok'. */
+ Dwarf_Bool pf_std_op_count;
+
+};
+
+void dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf);
+void dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf);
+
+int dwarf_read_line_table_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * data_start,
+ Dwarf_Unsigned data_length,
+ Dwarf_Small ** updated_data_start_out,
+ struct Line_Table_Prefix_s *prefix_out,
+ /* The following 2 arguments are solely for warning users
+ * when there is a surprising 'gap' in the .debug_line info. */
+ Dwarf_Small ** bogus_bytes_ptr,
+ Dwarf_Unsigned * bogus_bytes_count,
+ Dwarf_Error * err,
+ int * err_count_out);
diff --git a/usr/src/lib/libdwarf/common/dwarf_line2.c b/usr/src/lib/libdwarf/common/dwarf_line2.c
new file mode 100644
index 0000000000..634b848167
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line2.c
@@ -0,0 +1,110 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+/* This source file used for SGI-IRIX rqs processing.
+ Unused otherwise.
+*/
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_line.h"
+
+/*
+ Return DW_DLV_OK or, if error,
+ DW_DLV_ERROR.
+
+ Thru pointers, return 2 arrays and a count
+ for rqs.
+*/
+int
+_dwarf_line_address_offsets(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offs,
+ Dwarf_Unsigned * returncount,
+ Dwarf_Error * err)
+{
+ Dwarf_Addr *laddrs;
+ Dwarf_Off *loffsets;
+ Dwarf_Signed lcount;
+ Dwarf_Signed i;
+ int res;
+ Dwarf_Line *linebuf;
+
+ res = _dwarf_internal_srclines(die, &linebuf, &lcount, /* addrlist=
+ */ true,
+ /* linelist= */ false, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ laddrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
+ if (laddrs == NULL) {
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ loffsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
+ if (loffsets == NULL) {
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ /* We already allocated what laddrs points at, so we'e better
+ deallocate that space since we are not going to return the
+ pointer to the caller. */
+ dwarf_dealloc(dbg, laddrs, DW_DLA_ADDR);
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ for (i = 0; i < lcount; i++) {
+ laddrs[i] = linebuf[i]->li_address;
+ loffsets[i] = linebuf[i]->li_addr_line.li_offset;
+ }
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ *returncount = lcount;
+ *offs = loffsets;
+ *addrs = laddrs;
+ return DW_DLV_OK;
+}
+
+/*
+ It's impossible for callers of dwarf_srclines() to get to and
+ free all the resources (in particular, the li_context and its
+ lc_file_entries).
+ So this function, new July 2005, does it.
+*/
diff --git a/usr/src/lib/libdwarf/common/dwarf_loc.c b/usr/src/lib/libdwarf/common/dwarf_loc.c
new file mode 100644
index 0000000000..f28b27b630
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_loc.c
@@ -0,0 +1,1073 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_loc.h"
+#include <stdio.h> /* for debugging only. */
+#include <sys/types.h>
+
+/*
+ Given a Dwarf_Block that represents a location expression,
+ this function returns a pointer to a Dwarf_Locdesc struct
+ that has its ld_cents field set to the number of location
+ operators in the block, and its ld_s field pointing to a
+ contiguous block of Dwarf_Loc structs. However, the
+ ld_lopc and ld_hipc values are uninitialized. Returns
+ NULL on error. This function assumes that the length of
+ the block is greater than 0. Zero length location expressions
+ to represent variables that have been optimized away are
+ handled in the calling function.
+*/
+static Dwarf_Locdesc *
+_dwarf_get_locdesc(Dwarf_Debug dbg,
+ Dwarf_Block * loc_block,
+ Dwarf_Half address_size,
+ Dwarf_Addr lowpc,
+ Dwarf_Addr highpc,
+ Dwarf_Error * error)
+{
+ /* Size of the block containing the location expression. */
+ Dwarf_Unsigned loc_len = 0;
+
+ /* Sweeps the block containing the location expression. */
+ Dwarf_Small *loc_ptr = 0;
+
+ /* Current location operator. */
+ Dwarf_Small atom = 0;
+
+ /* Offset of current operator from start of block. */
+ Dwarf_Unsigned offset = 0;
+
+ /* Operands of current location operator. */
+ Dwarf_Unsigned operand1, operand2;
+
+ /* Used to chain the Dwarf_Loc_Chain_s structs. */
+ Dwarf_Loc_Chain curr_loc = NULL;
+ Dwarf_Loc_Chain prev_loc = NULL;
+ Dwarf_Loc_Chain head_loc = NULL;
+
+ /* Count of the number of location operators. */
+ Dwarf_Unsigned op_count = 0;
+
+ /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
+ Dwarf_Loc *block_loc = 0;
+
+ /* Dwarf_Locdesc pointer to be returned. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned i = 0;
+
+ /* ***** BEGIN CODE ***** */
+
+ loc_len = loc_block->bl_len;
+ loc_ptr = loc_block->bl_data;
+
+ offset = 0;
+ op_count = 0;
+ while (offset < loc_len) {
+
+ operand1 = 0;
+ operand2 = 0;
+ op_count++;
+
+ atom = *(Dwarf_Small *) loc_ptr;
+ loc_ptr++;
+ offset++;
+
+ curr_loc =
+ (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN,
+ 1);
+ if (curr_loc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+ curr_loc->lc_offset = offset;
+ curr_loc->lc_atom = atom;
+ switch (atom) {
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+
+ case DW_OP_regx:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ operand1 = atom - DW_OP_lit0;
+ break;
+
+ case DW_OP_addr:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned,
+ loc_ptr, address_size);
+ loc_ptr += address_size;
+ offset += address_size;
+ break;
+
+ case DW_OP_const1u:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_const1s:
+ operand1 = *(Dwarf_Sbyte *) loc_ptr;
+ SIGN_EXTEND(operand1,1);
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_const2u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_const2s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ SIGN_EXTEND(operand1,2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_const4u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+
+ case DW_OP_const4s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ SIGN_EXTEND(operand1,4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+
+ case DW_OP_const8u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
+ loc_ptr = loc_ptr + 8;
+ offset = offset + 8;
+ break;
+
+ case DW_OP_const8s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
+ loc_ptr = loc_ptr + 8;
+ offset = offset + 8;
+ break;
+
+ case DW_OP_constu:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_consts:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_fbreg:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_bregx:
+ /* uleb reg num followed by sleb offset */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_dup:
+ case DW_OP_drop:
+ break;
+
+ case DW_OP_pick:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ break;
+
+ case DW_OP_deref_size:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_xderef:
+ break;
+
+ case DW_OP_xderef_size:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ break;
+
+ case DW_OP_plus_uconst:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ break;
+
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ break;
+
+ case DW_OP_skip:
+ case DW_OP_bra:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_piece:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_nop:
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_call4: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+ case DW_OP_call_ref: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr,
+ dbg->de_length_size);
+ loc_ptr = loc_ptr + dbg->de_length_size;
+ offset = offset + dbg->de_length_size;
+ break;
+
+ case DW_OP_form_tls_address: /* DWARF3f */
+ break;
+ case DW_OP_call_frame_cfa: /* DWARF3f */
+ break;
+ case DW_OP_bit_piece: /* DWARF3f */
+ /* uleb size in bits followed by uleb offset in bits */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ operand2 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+ case DW_OP_implicit_value: /* DWARF4 */
+ /* uleb length of value bytes followed by that
+ number of bytes of the value. */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ /* Second operand is block of 'operand1' bytes of stuff. */
+ /* This using the second operand as a pointer
+ is quite ugly. */
+ /* This gets an ugly compiler warning. Sorry. */
+ operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
+ offset = offset + operand1;
+ loc_ptr = loc_ptr + operand1;
+ break;
+ case DW_OP_stack_value: /* DWARF4 */
+ break;
+
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return (NULL);
+ }
+
+
+ curr_loc->lc_number = operand1;
+ curr_loc->lc_number2 = operand2;
+
+ if (head_loc == NULL)
+ head_loc = prev_loc = curr_loc;
+ else {
+ prev_loc->lc_next = curr_loc;
+ prev_loc = curr_loc;
+ }
+ }
+
+ block_loc =
+ (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count);
+ if (block_loc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ curr_loc = head_loc;
+ for (i = 0; i < op_count; i++) {
+ (block_loc + i)->lr_atom = curr_loc->lc_atom;
+ (block_loc + i)->lr_number = curr_loc->lc_number;
+ (block_loc + i)->lr_number2 = curr_loc->lc_number2;
+ (block_loc + i)->lr_offset = curr_loc->lc_offset;
+
+ prev_loc = curr_loc;
+ curr_loc = curr_loc->lc_next;
+ dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
+ }
+
+ locdesc =
+ (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
+ if (locdesc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ locdesc->ld_cents = op_count;
+ locdesc->ld_s = block_loc;
+ locdesc->ld_from_loclist = loc_block->bl_from_loclist;
+ locdesc->ld_section_offset = loc_block->bl_section_offset;
+ locdesc->ld_lopc = lowpc;
+ locdesc->ld_hipc = highpc;
+
+ return (locdesc);
+}
+
+/* Using a loclist offset to get the in-memory
+ address of .debug_loc data to read, returns the loclist
+ 'header' info in return_block.
+*/
+
+#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
+
+static int
+_dwarf_read_loc_section(Dwarf_Debug dbg,
+ Dwarf_Block * return_block,
+ Dwarf_Addr * lowpc, Dwarf_Addr * hipc,
+ Dwarf_Off sec_offset,
+ Dwarf_Half address_size,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset;
+
+ Dwarf_Addr start_addr = 0;
+ Dwarf_Addr end_addr = 0;
+ Dwarf_Half exprblock_size = 0;
+ Dwarf_Unsigned exprblock_off =
+ 2 * address_size + sizeof(Dwarf_Half);
+
+ if (sec_offset >= dbg->de_debug_loc.dss_size) {
+ /* We're at the end. No more present. */
+ return DW_DLV_NO_ENTRY;
+ }
+
+ /* If it goes past end, error */
+ if (exprblock_off > dbg->de_debug_loc.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
+ return DW_DLV_ERROR;
+ }
+
+ READ_UNALIGNED(dbg, start_addr, Dwarf_Addr, beg, address_size);
+ READ_UNALIGNED(dbg, end_addr, Dwarf_Addr,
+ beg + address_size, address_size);
+ if (start_addr == 0 && end_addr == 0) {
+ /* If start_addr and end_addr are 0, it's the end and no
+ exprblock_size field follows. */
+ exprblock_size = 0;
+ exprblock_off -= sizeof(Dwarf_Half);
+ } else if (start_addr == MAX_ADDR) {
+ /* end address is a base address, no exprblock_size field here
+ either */
+ exprblock_size = 0;
+ exprblock_off -= sizeof(Dwarf_Half);
+ } else {
+
+ READ_UNALIGNED(dbg, exprblock_size, Dwarf_Half,
+ beg + 2 * address_size, sizeof(Dwarf_Half));
+ /* exprblock_size can be zero, means no expression */
+ if ((exprblock_off + exprblock_size) > dbg->de_debug_loc.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
+ return DW_DLV_ERROR;
+ }
+ }
+#undef MAX_ADDR
+ *lowpc = start_addr;
+ *hipc = end_addr;
+
+ return_block->bl_len = exprblock_size;
+ return_block->bl_from_loclist = 1;
+ return_block->bl_data = beg + exprblock_off;
+ return_block->bl_section_offset =
+ ((Dwarf_Small *) return_block->bl_data) - dbg->de_debug_loc.dss_data;
+
+ return DW_DLV_OK;
+
+}
+static int
+_dwarf_get_loclist_count(Dwarf_Debug dbg,
+ Dwarf_Off loclist_offset,
+ Dwarf_Half address_size,
+ int *loclist_count, Dwarf_Error * error)
+{
+ int count = 0;
+ Dwarf_Off offset = loclist_offset;
+
+
+ for (;;) {
+ Dwarf_Block b;
+ Dwarf_Addr lowpc;
+ Dwarf_Addr highpc;
+ int res = _dwarf_read_loc_section(dbg, &b,
+ &lowpc, &highpc,
+ offset, address_size,error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ offset = b.bl_len + b.bl_section_offset;
+ if (lowpc == 0 && highpc == 0) {
+ break;
+ }
+ count++;
+ }
+ *loclist_count = count;
+ return DW_DLV_OK;
+}
+
+/* Helper routine to avoid code duplication.
+*/
+static int
+_dwarf_setup_loc(Dwarf_Attribute attr,
+ Dwarf_Debug * dbg_ret,
+ Dwarf_CU_Context *cucontext_ret,
+ Dwarf_Half * form_ret, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half form = 0;
+ int blkres = DW_DLV_ERROR;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (attr->ar_cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+ *cucontext_ret = attr->ar_cu_context;
+
+ dbg = attr->ar_cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *dbg_ret = dbg;
+ blkres = dwarf_whatform(attr, &form, error);
+ if (blkres != DW_DLV_OK) {
+ _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return blkres;
+ }
+ *form_ret = form;
+ return DW_DLV_OK;
+}
+
+/* Helper routine to avoid code duplication.
+*/
+static int
+_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
+ Dwarf_Attribute attr,
+ Dwarf_Unsigned * loclist_offset,
+ Dwarf_Error * error)
+{
+ int blkres = dwarf_formudata(attr, loclist_offset, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+
+ if (!dbg->de_debug_loc.dss_data) {
+ int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
+ if (secload != DW_DLV_OK) {
+ return secload;
+ }
+ }
+ return DW_DLV_OK;
+}
+
+/* When llbuf (see dwarf_loclist_n) is partially set up
+ and an error is encountered, tear it down as it
+ won't be used.
+*/
+static void
+_dwarf_cleanup_llbuf(Dwarf_Debug dbg, Dwarf_Locdesc ** llbuf, int count)
+{
+ int i;
+ for (i = 0; i < count; ++i) {
+ dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dbg, llbuf[i], DW_DLA_LOCDESC);
+ }
+ dwarf_dealloc(dbg, llbuf, DW_DLA_LIST);
+}
+
+/*
+ Handles simple location entries and loclists.
+ Returns all the Locdesc's thru llbuf.
+
+*/
+int
+dwarf_loclist_n(Dwarf_Attribute attr,
+ Dwarf_Locdesc *** llbuf_out,
+ Dwarf_Signed * listlen_out, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ /*
+ Dwarf_Attribute that describes the DW_AT_location in die, if
+ present. */
+ Dwarf_Attribute loc_attr = attr;
+
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Half form = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_Signed listlen = 0;
+ Dwarf_Locdesc **llbuf = 0;
+ Dwarf_CU_Context cucontext = 0;
+ unsigned address_size = 0;
+
+ int blkres = DW_DLV_ERROR;
+ int setup_res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
+ if (setup_res != DW_DLV_OK) {
+ return setup_res;
+ }
+ address_size = cucontext->cc_address_size;
+ /* If this is a form_block then it's a location expression. If it's
+ DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
+ if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
+ cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
+ (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
+ (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
+ form == DW_FORM_sec_offset))
+ {
+
+
+ /* A reference to .debug_loc, with an offset in .debug_loc of a
+ loclist */
+ Dwarf_Unsigned loclist_offset = 0;
+ int off_res = DW_DLV_ERROR;
+ int count_res = DW_DLV_ERROR;
+ int loclist_count;
+ int lli;
+
+ off_res = _dwarf_get_loclist_header_start(dbg,
+ attr, &loclist_offset,
+ error);
+ if (off_res != DW_DLV_OK) {
+ return off_res;
+ }
+ count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
+ address_size,
+ &loclist_count, error);
+ listlen = loclist_count;
+ if (count_res != DW_DLV_OK) {
+ return count_res;
+ }
+ if (loclist_count == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ llbuf = (Dwarf_Locdesc **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count);
+ if (!llbuf) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ for (lli = 0; lli < loclist_count; ++lli) {
+ blkres = _dwarf_read_loc_section(dbg, &loc_block,
+ &lowpc,
+ &highpc,
+ loclist_offset,
+ address_size,
+ error);
+ if (blkres != DW_DLV_OK) {
+ _dwarf_cleanup_llbuf(dbg, llbuf, lli);
+ return (blkres);
+ }
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ _dwarf_cleanup_llbuf(dbg, llbuf, lli);
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+ llbuf[lli] = locdesc;
+
+ /* Now get to next loclist entry offset. */
+ loclist_offset = loc_block.bl_section_offset +
+ loc_block.bl_len;
+ }
+
+
+ } else {
+ Dwarf_Block *tblock = 0;
+
+ blkres = dwarf_formblock(loc_attr, &tblock, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ loc_block = *tblock;
+ /* We copied tblock contents to the stack var, so can dealloc
+ tblock now. Avoids leaks. */
+ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
+ listlen = 1; /* One by definition of a location entry. */
+ lowpc = 0; /* HACK */
+ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
+
+ /* An empty location description (block length 0) means the
+ code generator emitted no variable, the variable was not
+ generated, it was unused or perhaps never tested after being
+ set. Dwarf2, section 2.4.1 In other words, it is not an
+ error, and we don't test for block length 0 specially here. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+ llbuf = (Dwarf_Locdesc **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen);
+ if (!llbuf) {
+ /* Free the locdesc we allocated but won't use. */
+ dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ llbuf[0] = locdesc;
+ }
+
+ *llbuf_out = llbuf;
+ *listlen_out = listlen;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ Handles only a location expression.
+ If called on a loclist, just returns one of those.
+ Cannot not handle a real loclist.
+ It returns the location expression as a loclist with
+ a single entry.
+ See dwarf_loclist_n() which handles any number
+ of location list entries.
+
+ This is the original definition, and it simply
+ does not work for loclists. Kept for compatibility.
+*/
+int
+dwarf_loclist(Dwarf_Attribute attr,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ /* Dwarf_Attribute that describes the DW_AT_location in die, if
+ present. */
+ Dwarf_Attribute loc_attr = attr;
+
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Half form = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_CU_Context cucontext = 0;
+ unsigned address_size = 0;
+
+ int blkres = DW_DLV_ERROR;
+ int setup_res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error);
+ if (setup_res != DW_DLV_OK) {
+ return setup_res;
+ }
+ address_size = cucontext->cc_address_size;
+ /* If this is a form_block then it's a location expression. If it's
+ DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
+ if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
+ cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
+ (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
+ (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
+ form == DW_FORM_sec_offset))
+ {
+
+ /* A reference to .debug_loc, with an offset in .debug_loc of a
+ loclist */
+ Dwarf_Unsigned loclist_offset = 0;
+ int off_res = DW_DLV_ERROR;
+
+ off_res = _dwarf_get_loclist_header_start(dbg,
+ attr, &loclist_offset,
+ error);
+ if (off_res != DW_DLV_OK) {
+ return off_res;
+ }
+
+ /* With dwarf_loclist, just read a single entry */
+ blkres = _dwarf_read_loc_section(dbg, &loc_block,
+ &lowpc,
+ &highpc,
+ loclist_offset,
+ address_size,
+ error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ } else {
+ Dwarf_Block *tblock = 0;
+
+ blkres = dwarf_formblock(loc_attr, &tblock, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ loc_block = *tblock;
+ /* We copied tblock contents to the stack var, so can dealloc
+ tblock now. Avoids leaks. */
+ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
+ lowpc = 0; /* HACK */
+ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
+ }
+
+ /* An empty location description (block length 0) means the code
+ generator emitted no variable, the variable was not generated,
+ it was unused or perhaps never tested after being set. Dwarf2,
+ section 2.4.1 In other words, it is not an error, and we don't
+ test for block length 0 specially here.
+ See *dwarf_loclist_n() which handles the general case, this case
+ handles only a single location expression. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+
+ *llbuf = locdesc;
+ *listlen = 1;
+ return (DW_DLV_OK);
+}
+
+
+
+/*
+ Handles only a location expression.
+ It returns the location expression as a loclist with
+ a single entry.
+
+ Usable to access dwarf expressions from any source, but
+ specifically from
+ DW_CFA_def_cfa_expression
+ DW_CFA_expression
+ DW_CFA_val_expression
+
+ expression_in must point to a valid dwarf expression
+ set of bytes of length expression_length. Not
+ a DW_FORM_block*, just the expression bytes.
+
+ If the address_size != de_pointer_size this will not work
+ right. FIXME.
+*/
+int
+dwarf_loclist_from_expr(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ int res = 0;
+ Dwarf_Half addr_size = dbg->de_pointer_size;
+ res = dwarf_loclist_from_expr_a(dbg,expression_in,
+ expression_length, addr_size,llbuf,listlen,error);
+ return res;
+}
+/* New April 27 2009. Adding addr_size argument for the rare
+ * cases where an object has CUs with a different address_size. */
+int
+dwarf_loclist_from_expr_a(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Half addr_size,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = (Dwarf_Unsigned) (-1LL);
+
+ memset(&loc_block,0,sizeof(loc_block));
+ loc_block.bl_len = expression_length;
+ loc_block.bl_data = expression_in;
+ loc_block.bl_from_loclist = 0; /* Not from loclist. */
+ loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */
+
+ /* An empty location description (block length 0) means the code
+ generator emitted no variable, the variable was not generated,
+ it was unused or perhaps never tested after being set. Dwarf2,
+ section 2.4.1 In other words, it is not an error, and we don't
+ test for block length 0 specially here. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ addr_size,lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+
+ *llbuf = locdesc;
+ *listlen = 1;
+ return (DW_DLV_OK);
+}
+
+/* Usable to read a single loclist or to read a block of them
+ or to read an entire section's loclists.
+
+ It's broken because it's not safe to read a loclist entry
+ when we do not know the address size (in any object where
+ address size can vary by compilation unit).
+*/
+
+ /*ARGSUSED*/ int
+dwarf_get_loclist_entry(Dwarf_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Addr * hipc_offset,
+ Dwarf_Addr * lopc_offset,
+ Dwarf_Ptr * data,
+ Dwarf_Unsigned * entry_len,
+ Dwarf_Unsigned * next_entry,
+ Dwarf_Error * error)
+{
+ Dwarf_Block b;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_Half address_size = 0;
+ int res = DW_DLV_ERROR;
+
+ if (!dbg->de_debug_loc.dss_data) {
+ int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
+ if (secload != DW_DLV_OK) {
+ return secload;
+ }
+ }
+
+ /* FIXME: address_size is not necessarily the same in every frame. */
+ address_size = dbg->de_pointer_size;
+ res = _dwarf_read_loc_section(dbg,
+ &b, &lowpc, &highpc, offset,
+ address_size,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ *hipc_offset = highpc;
+ *lopc_offset = lowpc;
+ *entry_len = b.bl_len;
+ *data = b.bl_data;
+ *next_entry = b.bl_len + b.bl_section_offset;
+ return DW_DLV_OK;
+}
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_loc.h b/usr/src/lib/libdwarf/common/dwarf_loc.h
new file mode 100644
index 0000000000..685d199f29
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_loc.h
@@ -0,0 +1,46 @@
+/*
+
+ Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+typedef struct Dwarf_Loc_Chain_s *Dwarf_Loc_Chain;
+
+struct Dwarf_Loc_Chain_s {
+ Dwarf_Small lc_atom;
+ Dwarf_Unsigned lc_number;
+ Dwarf_Unsigned lc_number2;
+ Dwarf_Unsigned lc_offset;
+ Dwarf_Loc_Chain lc_next;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_macro.c b/usr/src/lib/libdwarf/common/dwarf_macro.c
new file mode 100644
index 0000000000..e1ff976d8c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_macro.c
@@ -0,0 +1,467 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <limits.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#include "dwarf_macro.h"
+
+
+#define LEFTPAREN '('
+#define RIGHTPAREN ')'
+#define SPACE ' '
+
+/*
+ Given the dwarf macro string, return a pointer to
+ the value. Returns pointer to 0 byte at end of string
+ if no value found (meaning the value is the empty string).
+
+ Only understands well-formed dwarf macinfo strings.
+*/
+char *
+dwarf_find_macro_value_start(char *str)
+{
+ char *lcp;
+ int funclike = 0;
+
+ for (lcp = str; *lcp; ++lcp) {
+ switch (*lcp) {
+ case LEFTPAREN:
+ funclike = 1;
+ break;
+ case RIGHTPAREN:
+ /* lcp+1 must be a space, and following char is the value */
+ return lcp + 2;
+ case SPACE:
+ /* we allow extraneous spaces inside macro parameter **
+ list, just in case... This is not really needed. */
+ if (!funclike) {
+ return lcp + 1;
+ }
+ break;
+ }
+ }
+ /* never found value: returns pointer to the 0 byte at end of
+ string */
+ return lcp;
+
+}
+
+
+/*
+ Try to keep fileindex correct in every Macro_Details
+ record by tracking file starts and ends.
+ Uses high water mark: space reused, not freed.
+ Presumption is that this makes sense for most uses.
+ STARTERMAX is set so that the array need not be expanded for
+ most files: it is the initial include file depth.
+*/
+struct macro_stack_s {
+ Dwarf_Signed *st_base;
+ long max;
+ long next_to_use;
+ int was_fault;
+};
+
+static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms);
+static void
+free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms)
+{
+ dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING);
+ _dwarf_reset_index_macro_stack(ms);
+}
+
+#define STARTERMAX 10
+static void
+_dwarf_reset_index_macro_stack(struct macro_stack_s *ms)
+{
+ ms->st_base = 0;
+ ms->max = 0;
+ ms->next_to_use = 0;
+ ms->was_fault = 0;
+}
+static int
+_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx,
+ struct macro_stack_s *ms)
+{
+ Dwarf_Signed *newbase;
+
+ if (ms->next_to_use >= ms->max) {
+ long new_size;
+
+ if (ms->max == 0) {
+ ms->max = STARTERMAX;
+ }
+ new_size = ms->max * 2;
+ newbase =
+ _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ new_size * sizeof(Dwarf_Signed));
+ if (newbase == 0) {
+ /* just leave the old array in place */
+ ms->was_fault = 1;
+ return DW_DLV_ERROR;
+ }
+ if(ms->st_base) {
+ memcpy(newbase, ms->st_base,
+ ms->next_to_use * sizeof(Dwarf_Signed));
+ dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING);
+ }
+ ms->st_base = newbase;
+ ms->max = new_size;
+ }
+ ms->st_base[ms->next_to_use] = indx;
+ ++ms->next_to_use;
+ return DW_DLV_OK;
+}
+
+static Dwarf_Signed
+_dwarf_macro_stack_pop_index(struct macro_stack_s *ms)
+{
+ if (ms->was_fault) {
+ return -1;
+ }
+ if (ms->next_to_use > 0) {
+ ms->next_to_use--;
+ return (ms->st_base[ms->next_to_use]);
+ } else {
+ ms->was_fault = 1;
+ }
+ return -1;
+}
+
+/* starting at macro_offset in .debug_macinfo,
+ if maximum_count is 0, treat as if it is infinite.
+ get macro data up thru
+ maximum_count entries or the end of a compilation
+ unit's entries (whichever comes first).
+*/
+
+int
+dwarf_get_macro_details(Dwarf_Debug dbg,
+ Dwarf_Off macro_offset,
+ Dwarf_Unsigned maximum_count,
+ Dwarf_Signed * entry_count,
+ Dwarf_Macro_Details ** details,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *macro_base = 0;
+ Dwarf_Small *pnext = 0;
+ Dwarf_Unsigned endloc = 0;
+ unsigned char uc = 0;
+ unsigned long depth = 0;
+ /* By section 6.3.2 Dwarf3 draft 8/9,
+ the base file should appear as
+ DW_MACINFO_start_file. See
+ http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html
+ on "[Bug debug/20253] New: [3.4/4.0 regression]:
+ Macro debug info broken due to lexer change" for how
+ gcc is broken in some versions. We no longer use
+ depth as a stopping point, it's not needed as a
+ stopping point anyway. */
+ int res = 0;
+ /* count space used by strings */
+ unsigned long str_space = 0;
+ int done = 0;
+ unsigned long space_needed = 0;
+ unsigned long string_offset = 0;
+ Dwarf_Small *return_data = 0;
+ Dwarf_Small *pdata = 0;
+ unsigned long final_count = 0;
+ Dwarf_Signed fileindex = -1;
+ Dwarf_Small *latest_str_loc = 0;
+ struct macro_stack_s msdata;
+
+ unsigned long count = 0;
+ unsigned long max_count = (unsigned long) maximum_count;
+
+ _dwarf_reset_index_macro_stack(&msdata);
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
+ if (res != DW_DLV_OK) {
+ free_macro_stack(dbg,&msdata);
+ return res;
+ }
+
+ macro_base = dbg->de_debug_macinfo.dss_data;
+ if (macro_base == NULL) {
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_NO_ENTRY);
+ }
+ if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ pnext = macro_base + macro_offset;
+ if (maximum_count == 0) {
+ max_count = ULONG_MAX;
+ }
+
+
+ /* how many entries and how much space will they take? */
+
+ endloc = (pnext - macro_base);
+ if (endloc >= dbg->de_debug_macinfo.dss_size) {
+ if (endloc == dbg->de_debug_macinfo.dss_size) {
+ /* normal: found last entry */
+ free_macro_stack(dbg,&msdata);
+ return DW_DLV_NO_ENTRY;
+ }
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+ for (count = 0; !done && count < max_count; ++count) {
+ unsigned long slen;
+ Dwarf_Word len;
+
+ uc = *pnext;
+ ++pnext; /* get past the type code */
+ switch (uc) {
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ /* line, string */
+ case DW_MACINFO_vendor_ext:
+ /* number, string */
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ slen = strlen((char *) pnext) + 1;
+ pnext += slen;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ str_space += slen;
+ break;
+ case DW_MACINFO_start_file:
+ /* line, file index */
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ ++depth;
+ break;
+
+ case DW_MACINFO_end_file:
+ if (--depth == 0) {
+ /* done = 1; no, do not stop here, at least one gcc had
+ the wrong depth settings in the gcc 3.4 timeframe. */
+ }
+ break; /* no string or number here */
+ case 0:
+ /* end of cu's entries */
+ done = 1;
+ break;
+ default:
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ /* bogus macinfo! */
+ }
+
+ endloc = (pnext - macro_base);
+ if (endloc == dbg->de_debug_macinfo.dss_size) {
+ done = 1;
+ } else if (endloc > dbg->de_debug_macinfo.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+ }
+ if (count == 0) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INTERNAL_ERR);
+ return (DW_DLV_ERROR);
+ }
+
+ /* we have 'count' array entries to allocate and str_space bytes of
+ string space to provide for. */
+
+ string_offset = count * sizeof(Dwarf_Macro_Details);
+
+ /* extra 2 not really needed */
+ space_needed = string_offset + str_space + 2;
+ return_data = pdata =
+ _dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
+ latest_str_loc = pdata + string_offset;
+ if (pdata == 0) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
+ return (DW_DLV_ERROR);
+ }
+ pnext = macro_base + macro_offset;
+
+ done = 0;
+
+ /* A series ends with a type code of 0. */
+
+ for (final_count = 0; !done && final_count < count; ++final_count) {
+ unsigned long slen;
+ Dwarf_Word len;
+ Dwarf_Unsigned v1;
+ Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
+ (final_count * sizeof (Dwarf_Macro_Details)));
+
+ endloc = (pnext - macro_base);
+ if (endloc > dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ uc = *pnext;
+ pdmd->dmd_offset = (pnext - macro_base);
+ pdmd->dmd_type = uc;
+ pdmd->dmd_fileindex = fileindex;
+ pdmd->dmd_lineno = 0;
+ pdmd->dmd_macro = 0;
+ ++pnext; /* get past the type code */
+ switch (uc) {
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ /* line, string */
+ case DW_MACINFO_vendor_ext:
+ /* number, string */
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_lineno = v1;
+
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ slen = strlen((char *) pnext) + 1;
+ strcpy((char *) latest_str_loc, (char *) pnext);
+ pdmd->dmd_macro = (char *) latest_str_loc;
+ latest_str_loc += slen;
+ pnext += slen;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ case DW_MACINFO_start_file:
+ /* Line, file index */
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_lineno = v1;
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_fileindex = v1;
+ (void) _dwarf_macro_stack_push_index(dbg, fileindex,
+ &msdata);
+ /* We ignore the error, we just let fileindex ** be -1 when
+ we pop this one. */
+ fileindex = v1;
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ break;
+
+ case DW_MACINFO_end_file:
+ fileindex = _dwarf_macro_stack_pop_index(&msdata);
+ break; /* no string or number here */
+ case 0:
+ /* Type code of 0 means the end of cu's entries. */
+ done = 1;
+ break;
+ default:
+ /* Bogus macinfo! */
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *entry_count = count;
+ *details = (Dwarf_Macro_Details *) return_data;
+ free_macro_stack(dbg,&msdata);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_macro.h b/usr/src/lib/libdwarf/common/dwarf_macro.h
new file mode 100644
index 0000000000..31ea2e6e67
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_macro.h
@@ -0,0 +1,44 @@
+/*
+
+ Copyright (C) 2000, 2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+/*
+
+
+ dwarf_macro.h
+
+ $Revision: 1.4 $ $Date: 2004/10/28 22:19:14 $
+
+*/
diff --git a/usr/src/lib/libdwarf/common/dwarf_names.c b/usr/src/lib/libdwarf/common/dwarf_names.c
new file mode 100644
index 0000000000..417e025690
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_names.c
@@ -0,0 +1,2408 @@
+/* Generated routines, do not edit. */
+/* Generated on May 22 2011 03:05:33 */
+
+/* BEGIN FILE */
+
+#include "dwarf.h"
+
+#include "libdwarf.h"
+
+/* ARGSUSED */
+int
+dwarf_get_TAG_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_TAG_array_type:
+ *s_out = "DW_TAG_array_type";
+ return DW_DLV_OK;
+ case DW_TAG_class_type:
+ *s_out = "DW_TAG_class_type";
+ return DW_DLV_OK;
+ case DW_TAG_entry_point:
+ *s_out = "DW_TAG_entry_point";
+ return DW_DLV_OK;
+ case DW_TAG_enumeration_type:
+ *s_out = "DW_TAG_enumeration_type";
+ return DW_DLV_OK;
+ case DW_TAG_formal_parameter:
+ *s_out = "DW_TAG_formal_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_imported_declaration:
+ *s_out = "DW_TAG_imported_declaration";
+ return DW_DLV_OK;
+ case DW_TAG_label:
+ *s_out = "DW_TAG_label";
+ return DW_DLV_OK;
+ case DW_TAG_lexical_block:
+ *s_out = "DW_TAG_lexical_block";
+ return DW_DLV_OK;
+ case DW_TAG_member:
+ *s_out = "DW_TAG_member";
+ return DW_DLV_OK;
+ case DW_TAG_pointer_type:
+ *s_out = "DW_TAG_pointer_type";
+ return DW_DLV_OK;
+ case DW_TAG_reference_type:
+ *s_out = "DW_TAG_reference_type";
+ return DW_DLV_OK;
+ case DW_TAG_compile_unit:
+ *s_out = "DW_TAG_compile_unit";
+ return DW_DLV_OK;
+ case DW_TAG_string_type:
+ *s_out = "DW_TAG_string_type";
+ return DW_DLV_OK;
+ case DW_TAG_structure_type:
+ *s_out = "DW_TAG_structure_type";
+ return DW_DLV_OK;
+ case DW_TAG_subroutine_type:
+ *s_out = "DW_TAG_subroutine_type";
+ return DW_DLV_OK;
+ case DW_TAG_typedef:
+ *s_out = "DW_TAG_typedef";
+ return DW_DLV_OK;
+ case DW_TAG_union_type:
+ *s_out = "DW_TAG_union_type";
+ return DW_DLV_OK;
+ case DW_TAG_unspecified_parameters:
+ *s_out = "DW_TAG_unspecified_parameters";
+ return DW_DLV_OK;
+ case DW_TAG_variant:
+ *s_out = "DW_TAG_variant";
+ return DW_DLV_OK;
+ case DW_TAG_common_block:
+ *s_out = "DW_TAG_common_block";
+ return DW_DLV_OK;
+ case DW_TAG_common_inclusion:
+ *s_out = "DW_TAG_common_inclusion";
+ return DW_DLV_OK;
+ case DW_TAG_inheritance:
+ *s_out = "DW_TAG_inheritance";
+ return DW_DLV_OK;
+ case DW_TAG_inlined_subroutine:
+ *s_out = "DW_TAG_inlined_subroutine";
+ return DW_DLV_OK;
+ case DW_TAG_module:
+ *s_out = "DW_TAG_module";
+ return DW_DLV_OK;
+ case DW_TAG_ptr_to_member_type:
+ *s_out = "DW_TAG_ptr_to_member_type";
+ return DW_DLV_OK;
+ case DW_TAG_set_type:
+ *s_out = "DW_TAG_set_type";
+ return DW_DLV_OK;
+ case DW_TAG_subrange_type:
+ *s_out = "DW_TAG_subrange_type";
+ return DW_DLV_OK;
+ case DW_TAG_with_stmt:
+ *s_out = "DW_TAG_with_stmt";
+ return DW_DLV_OK;
+ case DW_TAG_access_declaration:
+ *s_out = "DW_TAG_access_declaration";
+ return DW_DLV_OK;
+ case DW_TAG_base_type:
+ *s_out = "DW_TAG_base_type";
+ return DW_DLV_OK;
+ case DW_TAG_catch_block:
+ *s_out = "DW_TAG_catch_block";
+ return DW_DLV_OK;
+ case DW_TAG_const_type:
+ *s_out = "DW_TAG_const_type";
+ return DW_DLV_OK;
+ case DW_TAG_constant:
+ *s_out = "DW_TAG_constant";
+ return DW_DLV_OK;
+ case DW_TAG_enumerator:
+ *s_out = "DW_TAG_enumerator";
+ return DW_DLV_OK;
+ case DW_TAG_file_type:
+ *s_out = "DW_TAG_file_type";
+ return DW_DLV_OK;
+ case DW_TAG_friend:
+ *s_out = "DW_TAG_friend";
+ return DW_DLV_OK;
+ case DW_TAG_namelist:
+ *s_out = "DW_TAG_namelist";
+ return DW_DLV_OK;
+ case DW_TAG_namelist_item:
+ *s_out = "DW_TAG_namelist_item";
+ return DW_DLV_OK;
+ case DW_TAG_packed_type:
+ *s_out = "DW_TAG_packed_type";
+ return DW_DLV_OK;
+ case DW_TAG_subprogram:
+ *s_out = "DW_TAG_subprogram";
+ return DW_DLV_OK;
+ case DW_TAG_template_type_parameter:
+ *s_out = "DW_TAG_template_type_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_template_value_parameter:
+ *s_out = "DW_TAG_template_value_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_thrown_type:
+ *s_out = "DW_TAG_thrown_type";
+ return DW_DLV_OK;
+ case DW_TAG_try_block:
+ *s_out = "DW_TAG_try_block";
+ return DW_DLV_OK;
+ case DW_TAG_variant_part:
+ *s_out = "DW_TAG_variant_part";
+ return DW_DLV_OK;
+ case DW_TAG_variable:
+ *s_out = "DW_TAG_variable";
+ return DW_DLV_OK;
+ case DW_TAG_volatile_type:
+ *s_out = "DW_TAG_volatile_type";
+ return DW_DLV_OK;
+ case DW_TAG_dwarf_procedure:
+ *s_out = "DW_TAG_dwarf_procedure";
+ return DW_DLV_OK;
+ case DW_TAG_restrict_type:
+ *s_out = "DW_TAG_restrict_type";
+ return DW_DLV_OK;
+ case DW_TAG_interface_type:
+ *s_out = "DW_TAG_interface_type";
+ return DW_DLV_OK;
+ case DW_TAG_namespace:
+ *s_out = "DW_TAG_namespace";
+ return DW_DLV_OK;
+ case DW_TAG_imported_module:
+ *s_out = "DW_TAG_imported_module";
+ return DW_DLV_OK;
+ case DW_TAG_unspecified_type:
+ *s_out = "DW_TAG_unspecified_type";
+ return DW_DLV_OK;
+ case DW_TAG_partial_unit:
+ *s_out = "DW_TAG_partial_unit";
+ return DW_DLV_OK;
+ case DW_TAG_imported_unit:
+ *s_out = "DW_TAG_imported_unit";
+ return DW_DLV_OK;
+ case DW_TAG_mutable_type:
+ *s_out = "DW_TAG_mutable_type";
+ return DW_DLV_OK;
+ case DW_TAG_condition:
+ *s_out = "DW_TAG_condition";
+ return DW_DLV_OK;
+ case DW_TAG_shared_type:
+ *s_out = "DW_TAG_shared_type";
+ return DW_DLV_OK;
+ case DW_TAG_type_unit:
+ *s_out = "DW_TAG_type_unit";
+ return DW_DLV_OK;
+ case DW_TAG_rvalue_reference_type:
+ *s_out = "DW_TAG_rvalue_reference_type";
+ return DW_DLV_OK;
+ case DW_TAG_template_alias:
+ *s_out = "DW_TAG_template_alias";
+ return DW_DLV_OK;
+ case DW_TAG_lo_user:
+ *s_out = "DW_TAG_lo_user";
+ return DW_DLV_OK;
+ case DW_TAG_MIPS_loop:
+ *s_out = "DW_TAG_MIPS_loop";
+ return DW_DLV_OK;
+ case DW_TAG_HP_array_descriptor:
+ *s_out = "DW_TAG_HP_array_descriptor";
+ return DW_DLV_OK;
+ case DW_TAG_format_label:
+ *s_out = "DW_TAG_format_label";
+ return DW_DLV_OK;
+ case DW_TAG_function_template:
+ *s_out = "DW_TAG_function_template";
+ return DW_DLV_OK;
+ case DW_TAG_class_template:
+ *s_out = "DW_TAG_class_template";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_BINCL:
+ *s_out = "DW_TAG_GNU_BINCL";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_EINCL:
+ *s_out = "DW_TAG_GNU_EINCL";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_template_template_parameter:
+ *s_out = "DW_TAG_GNU_template_template_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_template_parameter_pack:
+ *s_out = "DW_TAG_GNU_template_parameter_pack";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_formal_parameter_pack:
+ *s_out = "DW_TAG_GNU_formal_parameter_pack";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_function_template:
+ *s_out = "DW_TAG_SUN_function_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_class_template:
+ *s_out = "DW_TAG_SUN_class_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_struct_template:
+ *s_out = "DW_TAG_SUN_struct_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_union_template:
+ *s_out = "DW_TAG_SUN_union_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_indirect_inheritance:
+ *s_out = "DW_TAG_SUN_indirect_inheritance";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_codeflags:
+ *s_out = "DW_TAG_SUN_codeflags";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_memop_info:
+ *s_out = "DW_TAG_SUN_memop_info";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_omp_child_func:
+ *s_out = "DW_TAG_SUN_omp_child_func";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_rtti_descriptor:
+ *s_out = "DW_TAG_SUN_rtti_descriptor";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_dtor_info:
+ *s_out = "DW_TAG_SUN_dtor_info";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_dtor:
+ *s_out = "DW_TAG_SUN_dtor";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_f90_interface:
+ *s_out = "DW_TAG_SUN_f90_interface";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_fortran_vax_structure:
+ *s_out = "DW_TAG_SUN_fortran_vax_structure";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_hi:
+ *s_out = "DW_TAG_SUN_hi";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_circ_type:
+ *s_out = "DW_TAG_ALTIUM_circ_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_mwa_circ_type:
+ *s_out = "DW_TAG_ALTIUM_mwa_circ_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_rev_carry_type:
+ *s_out = "DW_TAG_ALTIUM_rev_carry_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_rom:
+ *s_out = "DW_TAG_ALTIUM_rom";
+ return DW_DLV_OK;
+ case DW_TAG_upc_shared_type:
+ *s_out = "DW_TAG_upc_shared_type";
+ return DW_DLV_OK;
+ case DW_TAG_upc_strict_type:
+ *s_out = "DW_TAG_upc_strict_type";
+ return DW_DLV_OK;
+ case DW_TAG_upc_relaxed_type:
+ *s_out = "DW_TAG_upc_relaxed_type";
+ return DW_DLV_OK;
+ case DW_TAG_PGI_kanji_type:
+ *s_out = "DW_TAG_PGI_kanji_type";
+ return DW_DLV_OK;
+ case DW_TAG_PGI_interface_block:
+ *s_out = "DW_TAG_PGI_interface_block";
+ return DW_DLV_OK;
+ case DW_TAG_hi_user:
+ *s_out = "DW_TAG_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_children_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_children_no:
+ *s_out = "DW_children_no";
+ return DW_DLV_OK;
+ case DW_children_yes:
+ *s_out = "DW_children_yes";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_FORM_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_FORM_addr:
+ *s_out = "DW_FORM_addr";
+ return DW_DLV_OK;
+ case DW_FORM_block2:
+ *s_out = "DW_FORM_block2";
+ return DW_DLV_OK;
+ case DW_FORM_block4:
+ *s_out = "DW_FORM_block4";
+ return DW_DLV_OK;
+ case DW_FORM_data2:
+ *s_out = "DW_FORM_data2";
+ return DW_DLV_OK;
+ case DW_FORM_data4:
+ *s_out = "DW_FORM_data4";
+ return DW_DLV_OK;
+ case DW_FORM_data8:
+ *s_out = "DW_FORM_data8";
+ return DW_DLV_OK;
+ case DW_FORM_string:
+ *s_out = "DW_FORM_string";
+ return DW_DLV_OK;
+ case DW_FORM_block:
+ *s_out = "DW_FORM_block";
+ return DW_DLV_OK;
+ case DW_FORM_block1:
+ *s_out = "DW_FORM_block1";
+ return DW_DLV_OK;
+ case DW_FORM_data1:
+ *s_out = "DW_FORM_data1";
+ return DW_DLV_OK;
+ case DW_FORM_flag:
+ *s_out = "DW_FORM_flag";
+ return DW_DLV_OK;
+ case DW_FORM_sdata:
+ *s_out = "DW_FORM_sdata";
+ return DW_DLV_OK;
+ case DW_FORM_strp:
+ *s_out = "DW_FORM_strp";
+ return DW_DLV_OK;
+ case DW_FORM_udata:
+ *s_out = "DW_FORM_udata";
+ return DW_DLV_OK;
+ case DW_FORM_ref_addr:
+ *s_out = "DW_FORM_ref_addr";
+ return DW_DLV_OK;
+ case DW_FORM_ref1:
+ *s_out = "DW_FORM_ref1";
+ return DW_DLV_OK;
+ case DW_FORM_ref2:
+ *s_out = "DW_FORM_ref2";
+ return DW_DLV_OK;
+ case DW_FORM_ref4:
+ *s_out = "DW_FORM_ref4";
+ return DW_DLV_OK;
+ case DW_FORM_ref8:
+ *s_out = "DW_FORM_ref8";
+ return DW_DLV_OK;
+ case DW_FORM_ref_udata:
+ *s_out = "DW_FORM_ref_udata";
+ return DW_DLV_OK;
+ case DW_FORM_indirect:
+ *s_out = "DW_FORM_indirect";
+ return DW_DLV_OK;
+ case DW_FORM_sec_offset:
+ *s_out = "DW_FORM_sec_offset";
+ return DW_DLV_OK;
+ case DW_FORM_exprloc:
+ *s_out = "DW_FORM_exprloc";
+ return DW_DLV_OK;
+ case DW_FORM_flag_present:
+ *s_out = "DW_FORM_flag_present";
+ return DW_DLV_OK;
+ case DW_FORM_ref_sig8:
+ *s_out = "DW_FORM_ref_sig8";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_AT_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_AT_sibling:
+ *s_out = "DW_AT_sibling";
+ return DW_DLV_OK;
+ case DW_AT_location:
+ *s_out = "DW_AT_location";
+ return DW_DLV_OK;
+ case DW_AT_name:
+ *s_out = "DW_AT_name";
+ return DW_DLV_OK;
+ case DW_AT_ordering:
+ *s_out = "DW_AT_ordering";
+ return DW_DLV_OK;
+ case DW_AT_subscr_data:
+ *s_out = "DW_AT_subscr_data";
+ return DW_DLV_OK;
+ case DW_AT_byte_size:
+ *s_out = "DW_AT_byte_size";
+ return DW_DLV_OK;
+ case DW_AT_bit_offset:
+ *s_out = "DW_AT_bit_offset";
+ return DW_DLV_OK;
+ case DW_AT_bit_size:
+ *s_out = "DW_AT_bit_size";
+ return DW_DLV_OK;
+ case DW_AT_element_list:
+ *s_out = "DW_AT_element_list";
+ return DW_DLV_OK;
+ case DW_AT_stmt_list:
+ *s_out = "DW_AT_stmt_list";
+ return DW_DLV_OK;
+ case DW_AT_low_pc:
+ *s_out = "DW_AT_low_pc";
+ return DW_DLV_OK;
+ case DW_AT_high_pc:
+ *s_out = "DW_AT_high_pc";
+ return DW_DLV_OK;
+ case DW_AT_language:
+ *s_out = "DW_AT_language";
+ return DW_DLV_OK;
+ case DW_AT_member:
+ *s_out = "DW_AT_member";
+ return DW_DLV_OK;
+ case DW_AT_discr:
+ *s_out = "DW_AT_discr";
+ return DW_DLV_OK;
+ case DW_AT_discr_value:
+ *s_out = "DW_AT_discr_value";
+ return DW_DLV_OK;
+ case DW_AT_visibility:
+ *s_out = "DW_AT_visibility";
+ return DW_DLV_OK;
+ case DW_AT_import:
+ *s_out = "DW_AT_import";
+ return DW_DLV_OK;
+ case DW_AT_string_length:
+ *s_out = "DW_AT_string_length";
+ return DW_DLV_OK;
+ case DW_AT_common_reference:
+ *s_out = "DW_AT_common_reference";
+ return DW_DLV_OK;
+ case DW_AT_comp_dir:
+ *s_out = "DW_AT_comp_dir";
+ return DW_DLV_OK;
+ case DW_AT_const_value:
+ *s_out = "DW_AT_const_value";
+ return DW_DLV_OK;
+ case DW_AT_containing_type:
+ *s_out = "DW_AT_containing_type";
+ return DW_DLV_OK;
+ case DW_AT_default_value:
+ *s_out = "DW_AT_default_value";
+ return DW_DLV_OK;
+ case DW_AT_inline:
+ *s_out = "DW_AT_inline";
+ return DW_DLV_OK;
+ case DW_AT_is_optional:
+ *s_out = "DW_AT_is_optional";
+ return DW_DLV_OK;
+ case DW_AT_lower_bound:
+ *s_out = "DW_AT_lower_bound";
+ return DW_DLV_OK;
+ case DW_AT_producer:
+ *s_out = "DW_AT_producer";
+ return DW_DLV_OK;
+ case DW_AT_prototyped:
+ *s_out = "DW_AT_prototyped";
+ return DW_DLV_OK;
+ case DW_AT_return_addr:
+ *s_out = "DW_AT_return_addr";
+ return DW_DLV_OK;
+ case DW_AT_start_scope:
+ *s_out = "DW_AT_start_scope";
+ return DW_DLV_OK;
+ case DW_AT_bit_stride:
+ *s_out = "DW_AT_bit_stride";
+ return DW_DLV_OK;
+ case DW_AT_upper_bound:
+ *s_out = "DW_AT_upper_bound";
+ return DW_DLV_OK;
+ case DW_AT_abstract_origin:
+ *s_out = "DW_AT_abstract_origin";
+ return DW_DLV_OK;
+ case DW_AT_accessibility:
+ *s_out = "DW_AT_accessibility";
+ return DW_DLV_OK;
+ case DW_AT_address_class:
+ *s_out = "DW_AT_address_class";
+ return DW_DLV_OK;
+ case DW_AT_artificial:
+ *s_out = "DW_AT_artificial";
+ return DW_DLV_OK;
+ case DW_AT_base_types:
+ *s_out = "DW_AT_base_types";
+ return DW_DLV_OK;
+ case DW_AT_calling_convention:
+ *s_out = "DW_AT_calling_convention";
+ return DW_DLV_OK;
+ case DW_AT_count:
+ *s_out = "DW_AT_count";
+ return DW_DLV_OK;
+ case DW_AT_data_member_location:
+ *s_out = "DW_AT_data_member_location";
+ return DW_DLV_OK;
+ case DW_AT_decl_column:
+ *s_out = "DW_AT_decl_column";
+ return DW_DLV_OK;
+ case DW_AT_decl_file:
+ *s_out = "DW_AT_decl_file";
+ return DW_DLV_OK;
+ case DW_AT_decl_line:
+ *s_out = "DW_AT_decl_line";
+ return DW_DLV_OK;
+ case DW_AT_declaration:
+ *s_out = "DW_AT_declaration";
+ return DW_DLV_OK;
+ case DW_AT_discr_list:
+ *s_out = "DW_AT_discr_list";
+ return DW_DLV_OK;
+ case DW_AT_encoding:
+ *s_out = "DW_AT_encoding";
+ return DW_DLV_OK;
+ case DW_AT_external:
+ *s_out = "DW_AT_external";
+ return DW_DLV_OK;
+ case DW_AT_frame_base:
+ *s_out = "DW_AT_frame_base";
+ return DW_DLV_OK;
+ case DW_AT_friend:
+ *s_out = "DW_AT_friend";
+ return DW_DLV_OK;
+ case DW_AT_identifier_case:
+ *s_out = "DW_AT_identifier_case";
+ return DW_DLV_OK;
+ case DW_AT_macro_info:
+ *s_out = "DW_AT_macro_info";
+ return DW_DLV_OK;
+ case DW_AT_namelist_item:
+ *s_out = "DW_AT_namelist_item";
+ return DW_DLV_OK;
+ case DW_AT_priority:
+ *s_out = "DW_AT_priority";
+ return DW_DLV_OK;
+ case DW_AT_segment:
+ *s_out = "DW_AT_segment";
+ return DW_DLV_OK;
+ case DW_AT_specification:
+ *s_out = "DW_AT_specification";
+ return DW_DLV_OK;
+ case DW_AT_static_link:
+ *s_out = "DW_AT_static_link";
+ return DW_DLV_OK;
+ case DW_AT_type:
+ *s_out = "DW_AT_type";
+ return DW_DLV_OK;
+ case DW_AT_use_location:
+ *s_out = "DW_AT_use_location";
+ return DW_DLV_OK;
+ case DW_AT_variable_parameter:
+ *s_out = "DW_AT_variable_parameter";
+ return DW_DLV_OK;
+ case DW_AT_virtuality:
+ *s_out = "DW_AT_virtuality";
+ return DW_DLV_OK;
+ case DW_AT_vtable_elem_location:
+ *s_out = "DW_AT_vtable_elem_location";
+ return DW_DLV_OK;
+ case DW_AT_allocated:
+ *s_out = "DW_AT_allocated";
+ return DW_DLV_OK;
+ case DW_AT_associated:
+ *s_out = "DW_AT_associated";
+ return DW_DLV_OK;
+ case DW_AT_data_location:
+ *s_out = "DW_AT_data_location";
+ return DW_DLV_OK;
+ case DW_AT_stride:
+ *s_out = "DW_AT_stride";
+ return DW_DLV_OK;
+ case DW_AT_entry_pc:
+ *s_out = "DW_AT_entry_pc";
+ return DW_DLV_OK;
+ case DW_AT_use_UTF8:
+ *s_out = "DW_AT_use_UTF8";
+ return DW_DLV_OK;
+ case DW_AT_extension:
+ *s_out = "DW_AT_extension";
+ return DW_DLV_OK;
+ case DW_AT_ranges:
+ *s_out = "DW_AT_ranges";
+ return DW_DLV_OK;
+ case DW_AT_trampoline:
+ *s_out = "DW_AT_trampoline";
+ return DW_DLV_OK;
+ case DW_AT_call_column:
+ *s_out = "DW_AT_call_column";
+ return DW_DLV_OK;
+ case DW_AT_call_file:
+ *s_out = "DW_AT_call_file";
+ return DW_DLV_OK;
+ case DW_AT_call_line:
+ *s_out = "DW_AT_call_line";
+ return DW_DLV_OK;
+ case DW_AT_description:
+ *s_out = "DW_AT_description";
+ return DW_DLV_OK;
+ case DW_AT_binary_scale:
+ *s_out = "DW_AT_binary_scale";
+ return DW_DLV_OK;
+ case DW_AT_decimal_scale:
+ *s_out = "DW_AT_decimal_scale";
+ return DW_DLV_OK;
+ case DW_AT_small:
+ *s_out = "DW_AT_small";
+ return DW_DLV_OK;
+ case DW_AT_decimal_sign:
+ *s_out = "DW_AT_decimal_sign";
+ return DW_DLV_OK;
+ case DW_AT_digit_count:
+ *s_out = "DW_AT_digit_count";
+ return DW_DLV_OK;
+ case DW_AT_picture_string:
+ *s_out = "DW_AT_picture_string";
+ return DW_DLV_OK;
+ case DW_AT_mutable:
+ *s_out = "DW_AT_mutable";
+ return DW_DLV_OK;
+ case DW_AT_threads_scaled:
+ *s_out = "DW_AT_threads_scaled";
+ return DW_DLV_OK;
+ case DW_AT_explicit:
+ *s_out = "DW_AT_explicit";
+ return DW_DLV_OK;
+ case DW_AT_object_pointer:
+ *s_out = "DW_AT_object_pointer";
+ return DW_DLV_OK;
+ case DW_AT_endianity:
+ *s_out = "DW_AT_endianity";
+ return DW_DLV_OK;
+ case DW_AT_elemental:
+ *s_out = "DW_AT_elemental";
+ return DW_DLV_OK;
+ case DW_AT_pure:
+ *s_out = "DW_AT_pure";
+ return DW_DLV_OK;
+ case DW_AT_recursive:
+ *s_out = "DW_AT_recursive";
+ return DW_DLV_OK;
+ case DW_AT_signature:
+ *s_out = "DW_AT_signature";
+ return DW_DLV_OK;
+ case DW_AT_main_subprogram:
+ *s_out = "DW_AT_main_subprogram";
+ return DW_DLV_OK;
+ case DW_AT_data_bit_offset:
+ *s_out = "DW_AT_data_bit_offset";
+ return DW_DLV_OK;
+ case DW_AT_const_expr:
+ *s_out = "DW_AT_const_expr";
+ return DW_DLV_OK;
+ case DW_AT_enum_class:
+ *s_out = "DW_AT_enum_class";
+ return DW_DLV_OK;
+ case DW_AT_linkage_name:
+ *s_out = "DW_AT_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_lo_user:
+ *s_out = "DW_AT_lo_user";
+ return DW_DLV_OK;
+ case DW_AT_HP_unmodifiable:
+ *s_out = "DW_AT_HP_unmodifiable";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_loop_begin:
+ *s_out = "DW_AT_MIPS_loop_begin";
+ return DW_DLV_OK;
+ case DW_AT_CPQ_split_lifetimes_var:
+ *s_out = "DW_AT_CPQ_split_lifetimes_var";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_epilog_begin:
+ *s_out = "DW_AT_MIPS_epilog_begin";
+ return DW_DLV_OK;
+ case DW_AT_CPQ_prologue_length:
+ *s_out = "DW_AT_CPQ_prologue_length";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_software_pipeline_depth:
+ *s_out = "DW_AT_MIPS_software_pipeline_depth";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_linkage_name:
+ *s_out = "DW_AT_MIPS_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride:
+ *s_out = "DW_AT_MIPS_stride";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_abstract_name:
+ *s_out = "DW_AT_MIPS_abstract_name";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_clone_origin:
+ *s_out = "DW_AT_MIPS_clone_origin";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_has_inlines:
+ *s_out = "DW_AT_MIPS_has_inlines";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride_byte:
+ *s_out = "DW_AT_MIPS_stride_byte";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride_elem:
+ *s_out = "DW_AT_MIPS_stride_elem";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_ptr_dopetype:
+ *s_out = "DW_AT_MIPS_ptr_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_allocatable_dopetype:
+ *s_out = "DW_AT_MIPS_allocatable_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_assumed_shape_dopetype:
+ *s_out = "DW_AT_MIPS_assumed_shape_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_HP_proc_per_section:
+ *s_out = "DW_AT_HP_proc_per_section";
+ return DW_DLV_OK;
+ case DW_AT_HP_raw_data_ptr:
+ *s_out = "DW_AT_HP_raw_data_ptr";
+ return DW_DLV_OK;
+ case DW_AT_HP_pass_by_reference:
+ *s_out = "DW_AT_HP_pass_by_reference";
+ return DW_DLV_OK;
+ case DW_AT_HP_opt_level:
+ *s_out = "DW_AT_HP_opt_level";
+ return DW_DLV_OK;
+ case DW_AT_HP_prof_version_id:
+ *s_out = "DW_AT_HP_prof_version_id";
+ return DW_DLV_OK;
+ case DW_AT_HP_opt_flags:
+ *s_out = "DW_AT_HP_opt_flags";
+ return DW_DLV_OK;
+ case DW_AT_HP_cold_region_low_pc:
+ *s_out = "DW_AT_HP_cold_region_low_pc";
+ return DW_DLV_OK;
+ case DW_AT_HP_cold_region_high_pc:
+ *s_out = "DW_AT_HP_cold_region_high_pc";
+ return DW_DLV_OK;
+ case DW_AT_HP_all_variables_modifiable:
+ *s_out = "DW_AT_HP_all_variables_modifiable";
+ return DW_DLV_OK;
+ case DW_AT_HP_linkage_name:
+ *s_out = "DW_AT_HP_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_HP_prof_flags:
+ *s_out = "DW_AT_HP_prof_flags";
+ return DW_DLV_OK;
+ case DW_AT_INTEL_other_endian:
+ *s_out = "DW_AT_INTEL_other_endian";
+ return DW_DLV_OK;
+ case DW_AT_sf_names:
+ *s_out = "DW_AT_sf_names";
+ return DW_DLV_OK;
+ case DW_AT_src_info:
+ *s_out = "DW_AT_src_info";
+ return DW_DLV_OK;
+ case DW_AT_mac_info:
+ *s_out = "DW_AT_mac_info";
+ return DW_DLV_OK;
+ case DW_AT_src_coords:
+ *s_out = "DW_AT_src_coords";
+ return DW_DLV_OK;
+ case DW_AT_body_begin:
+ *s_out = "DW_AT_body_begin";
+ return DW_DLV_OK;
+ case DW_AT_body_end:
+ *s_out = "DW_AT_body_end";
+ return DW_DLV_OK;
+ case DW_AT_GNU_vector:
+ *s_out = "DW_AT_GNU_vector";
+ return DW_DLV_OK;
+ case DW_AT_GNU_template_name:
+ *s_out = "DW_AT_GNU_template_name";
+ return DW_DLV_OK;
+ case DW_AT_VMS_rtnbeg_pd_address:
+ *s_out = "DW_AT_VMS_rtnbeg_pd_address";
+ return DW_DLV_OK;
+ case DW_AT_SUN_alignment:
+ *s_out = "DW_AT_SUN_alignment";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable:
+ *s_out = "DW_AT_SUN_vtable";
+ return DW_DLV_OK;
+ case DW_AT_SUN_count_guarantee:
+ *s_out = "DW_AT_SUN_count_guarantee";
+ return DW_DLV_OK;
+ case DW_AT_SUN_command_line:
+ *s_out = "DW_AT_SUN_command_line";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vbase:
+ *s_out = "DW_AT_SUN_vbase";
+ return DW_DLV_OK;
+ case DW_AT_SUN_compile_options:
+ *s_out = "DW_AT_SUN_compile_options";
+ return DW_DLV_OK;
+ case DW_AT_SUN_language:
+ *s_out = "DW_AT_SUN_language";
+ return DW_DLV_OK;
+ case DW_AT_SUN_browser_file:
+ *s_out = "DW_AT_SUN_browser_file";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable_abi:
+ *s_out = "DW_AT_SUN_vtable_abi";
+ return DW_DLV_OK;
+ case DW_AT_SUN_func_offsets:
+ *s_out = "DW_AT_SUN_func_offsets";
+ return DW_DLV_OK;
+ case DW_AT_SUN_cf_kind:
+ *s_out = "DW_AT_SUN_cf_kind";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable_index:
+ *s_out = "DW_AT_SUN_vtable_index";
+ return DW_DLV_OK;
+ case DW_AT_SUN_omp_tpriv_addr:
+ *s_out = "DW_AT_SUN_omp_tpriv_addr";
+ return DW_DLV_OK;
+ case DW_AT_SUN_omp_child_func:
+ *s_out = "DW_AT_SUN_omp_child_func";
+ return DW_DLV_OK;
+ case DW_AT_SUN_func_offset:
+ *s_out = "DW_AT_SUN_func_offset";
+ return DW_DLV_OK;
+ case DW_AT_SUN_memop_type_ref:
+ *s_out = "DW_AT_SUN_memop_type_ref";
+ return DW_DLV_OK;
+ case DW_AT_SUN_profile_id:
+ *s_out = "DW_AT_SUN_profile_id";
+ return DW_DLV_OK;
+ case DW_AT_SUN_memop_signature:
+ *s_out = "DW_AT_SUN_memop_signature";
+ return DW_DLV_OK;
+ case DW_AT_SUN_obj_dir:
+ *s_out = "DW_AT_SUN_obj_dir";
+ return DW_DLV_OK;
+ case DW_AT_SUN_obj_file:
+ *s_out = "DW_AT_SUN_obj_file";
+ return DW_DLV_OK;
+ case DW_AT_SUN_original_name:
+ *s_out = "DW_AT_SUN_original_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_hwcprof_signature:
+ *s_out = "DW_AT_SUN_hwcprof_signature";
+ return DW_DLV_OK;
+ case DW_AT_SUN_amd64_parmdump:
+ *s_out = "DW_AT_SUN_amd64_parmdump";
+ return DW_DLV_OK;
+ case DW_AT_SUN_part_link_name:
+ *s_out = "DW_AT_SUN_part_link_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_link_name:
+ *s_out = "DW_AT_SUN_link_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_pass_with_const:
+ *s_out = "DW_AT_SUN_pass_with_const";
+ return DW_DLV_OK;
+ case DW_AT_SUN_return_with_const:
+ *s_out = "DW_AT_SUN_return_with_const";
+ return DW_DLV_OK;
+ case DW_AT_SUN_import_by_name:
+ *s_out = "DW_AT_SUN_import_by_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_pointer:
+ *s_out = "DW_AT_SUN_f90_pointer";
+ return DW_DLV_OK;
+ case DW_AT_SUN_pass_by_ref:
+ *s_out = "DW_AT_SUN_pass_by_ref";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_allocatable:
+ *s_out = "DW_AT_SUN_f90_allocatable";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_assumed_shape_array:
+ *s_out = "DW_AT_SUN_f90_assumed_shape_array";
+ return DW_DLV_OK;
+ case DW_AT_SUN_c_vla:
+ *s_out = "DW_AT_SUN_c_vla";
+ return DW_DLV_OK;
+ case DW_AT_SUN_return_value_ptr:
+ *s_out = "DW_AT_SUN_return_value_ptr";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_start:
+ *s_out = "DW_AT_SUN_dtor_start";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_length:
+ *s_out = "DW_AT_SUN_dtor_length";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_initial:
+ *s_out = "DW_AT_SUN_dtor_state_initial";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_final:
+ *s_out = "DW_AT_SUN_dtor_state_final";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_deltas:
+ *s_out = "DW_AT_SUN_dtor_state_deltas";
+ return DW_DLV_OK;
+ case DW_AT_SUN_import_by_lname:
+ *s_out = "DW_AT_SUN_import_by_lname";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_use_only:
+ *s_out = "DW_AT_SUN_f90_use_only";
+ return DW_DLV_OK;
+ case DW_AT_SUN_namelist_spec:
+ *s_out = "DW_AT_SUN_namelist_spec";
+ return DW_DLV_OK;
+ case DW_AT_SUN_is_omp_child_func:
+ *s_out = "DW_AT_SUN_is_omp_child_func";
+ return DW_DLV_OK;
+ case DW_AT_SUN_fortran_main_alias:
+ *s_out = "DW_AT_SUN_fortran_main_alias";
+ return DW_DLV_OK;
+ case DW_AT_SUN_fortran_based:
+ *s_out = "DW_AT_SUN_fortran_based";
+ return DW_DLV_OK;
+ case DW_AT_ALTIUM_loclist:
+ *s_out = "DW_AT_ALTIUM_loclist";
+ return DW_DLV_OK;
+ case DW_AT_upc_threads_scaled:
+ *s_out = "DW_AT_upc_threads_scaled";
+ return DW_DLV_OK;
+ case DW_AT_PGI_lbase:
+ *s_out = "DW_AT_PGI_lbase";
+ return DW_DLV_OK;
+ case DW_AT_PGI_soffset:
+ *s_out = "DW_AT_PGI_soffset";
+ return DW_DLV_OK;
+ case DW_AT_PGI_lstride:
+ *s_out = "DW_AT_PGI_lstride";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_closure:
+ *s_out = "DW_AT_APPLE_closure";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_major_runtime_vers:
+ *s_out = "DW_AT_APPLE_major_runtime_vers";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_runtime_class:
+ *s_out = "DW_AT_APPLE_runtime_class";
+ return DW_DLV_OK;
+ case DW_AT_hi_user:
+ *s_out = "DW_AT_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_OP_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_OP_addr:
+ *s_out = "DW_OP_addr";
+ return DW_DLV_OK;
+ case DW_OP_deref:
+ *s_out = "DW_OP_deref";
+ return DW_DLV_OK;
+ case DW_OP_const1u:
+ *s_out = "DW_OP_const1u";
+ return DW_DLV_OK;
+ case DW_OP_const1s:
+ *s_out = "DW_OP_const1s";
+ return DW_DLV_OK;
+ case DW_OP_const2u:
+ *s_out = "DW_OP_const2u";
+ return DW_DLV_OK;
+ case DW_OP_const2s:
+ *s_out = "DW_OP_const2s";
+ return DW_DLV_OK;
+ case DW_OP_const4u:
+ *s_out = "DW_OP_const4u";
+ return DW_DLV_OK;
+ case DW_OP_const4s:
+ *s_out = "DW_OP_const4s";
+ return DW_DLV_OK;
+ case DW_OP_const8u:
+ *s_out = "DW_OP_const8u";
+ return DW_DLV_OK;
+ case DW_OP_const8s:
+ *s_out = "DW_OP_const8s";
+ return DW_DLV_OK;
+ case DW_OP_constu:
+ *s_out = "DW_OP_constu";
+ return DW_DLV_OK;
+ case DW_OP_consts:
+ *s_out = "DW_OP_consts";
+ return DW_DLV_OK;
+ case DW_OP_dup:
+ *s_out = "DW_OP_dup";
+ return DW_DLV_OK;
+ case DW_OP_drop:
+ *s_out = "DW_OP_drop";
+ return DW_DLV_OK;
+ case DW_OP_over:
+ *s_out = "DW_OP_over";
+ return DW_DLV_OK;
+ case DW_OP_pick:
+ *s_out = "DW_OP_pick";
+ return DW_DLV_OK;
+ case DW_OP_swap:
+ *s_out = "DW_OP_swap";
+ return DW_DLV_OK;
+ case DW_OP_rot:
+ *s_out = "DW_OP_rot";
+ return DW_DLV_OK;
+ case DW_OP_xderef:
+ *s_out = "DW_OP_xderef";
+ return DW_DLV_OK;
+ case DW_OP_abs:
+ *s_out = "DW_OP_abs";
+ return DW_DLV_OK;
+ case DW_OP_and:
+ *s_out = "DW_OP_and";
+ return DW_DLV_OK;
+ case DW_OP_div:
+ *s_out = "DW_OP_div";
+ return DW_DLV_OK;
+ case DW_OP_minus:
+ *s_out = "DW_OP_minus";
+ return DW_DLV_OK;
+ case DW_OP_mod:
+ *s_out = "DW_OP_mod";
+ return DW_DLV_OK;
+ case DW_OP_mul:
+ *s_out = "DW_OP_mul";
+ return DW_DLV_OK;
+ case DW_OP_neg:
+ *s_out = "DW_OP_neg";
+ return DW_DLV_OK;
+ case DW_OP_not:
+ *s_out = "DW_OP_not";
+ return DW_DLV_OK;
+ case DW_OP_or:
+ *s_out = "DW_OP_or";
+ return DW_DLV_OK;
+ case DW_OP_plus:
+ *s_out = "DW_OP_plus";
+ return DW_DLV_OK;
+ case DW_OP_plus_uconst:
+ *s_out = "DW_OP_plus_uconst";
+ return DW_DLV_OK;
+ case DW_OP_shl:
+ *s_out = "DW_OP_shl";
+ return DW_DLV_OK;
+ case DW_OP_shr:
+ *s_out = "DW_OP_shr";
+ return DW_DLV_OK;
+ case DW_OP_shra:
+ *s_out = "DW_OP_shra";
+ return DW_DLV_OK;
+ case DW_OP_xor:
+ *s_out = "DW_OP_xor";
+ return DW_DLV_OK;
+ case DW_OP_bra:
+ *s_out = "DW_OP_bra";
+ return DW_DLV_OK;
+ case DW_OP_eq:
+ *s_out = "DW_OP_eq";
+ return DW_DLV_OK;
+ case DW_OP_ge:
+ *s_out = "DW_OP_ge";
+ return DW_DLV_OK;
+ case DW_OP_gt:
+ *s_out = "DW_OP_gt";
+ return DW_DLV_OK;
+ case DW_OP_le:
+ *s_out = "DW_OP_le";
+ return DW_DLV_OK;
+ case DW_OP_lt:
+ *s_out = "DW_OP_lt";
+ return DW_DLV_OK;
+ case DW_OP_ne:
+ *s_out = "DW_OP_ne";
+ return DW_DLV_OK;
+ case DW_OP_skip:
+ *s_out = "DW_OP_skip";
+ return DW_DLV_OK;
+ case DW_OP_lit0:
+ *s_out = "DW_OP_lit0";
+ return DW_DLV_OK;
+ case DW_OP_lit1:
+ *s_out = "DW_OP_lit1";
+ return DW_DLV_OK;
+ case DW_OP_lit2:
+ *s_out = "DW_OP_lit2";
+ return DW_DLV_OK;
+ case DW_OP_lit3:
+ *s_out = "DW_OP_lit3";
+ return DW_DLV_OK;
+ case DW_OP_lit4:
+ *s_out = "DW_OP_lit4";
+ return DW_DLV_OK;
+ case DW_OP_lit5:
+ *s_out = "DW_OP_lit5";
+ return DW_DLV_OK;
+ case DW_OP_lit6:
+ *s_out = "DW_OP_lit6";
+ return DW_DLV_OK;
+ case DW_OP_lit7:
+ *s_out = "DW_OP_lit7";
+ return DW_DLV_OK;
+ case DW_OP_lit8:
+ *s_out = "DW_OP_lit8";
+ return DW_DLV_OK;
+ case DW_OP_lit9:
+ *s_out = "DW_OP_lit9";
+ return DW_DLV_OK;
+ case DW_OP_lit10:
+ *s_out = "DW_OP_lit10";
+ return DW_DLV_OK;
+ case DW_OP_lit11:
+ *s_out = "DW_OP_lit11";
+ return DW_DLV_OK;
+ case DW_OP_lit12:
+ *s_out = "DW_OP_lit12";
+ return DW_DLV_OK;
+ case DW_OP_lit13:
+ *s_out = "DW_OP_lit13";
+ return DW_DLV_OK;
+ case DW_OP_lit14:
+ *s_out = "DW_OP_lit14";
+ return DW_DLV_OK;
+ case DW_OP_lit15:
+ *s_out = "DW_OP_lit15";
+ return DW_DLV_OK;
+ case DW_OP_lit16:
+ *s_out = "DW_OP_lit16";
+ return DW_DLV_OK;
+ case DW_OP_lit17:
+ *s_out = "DW_OP_lit17";
+ return DW_DLV_OK;
+ case DW_OP_lit18:
+ *s_out = "DW_OP_lit18";
+ return DW_DLV_OK;
+ case DW_OP_lit19:
+ *s_out = "DW_OP_lit19";
+ return DW_DLV_OK;
+ case DW_OP_lit20:
+ *s_out = "DW_OP_lit20";
+ return DW_DLV_OK;
+ case DW_OP_lit21:
+ *s_out = "DW_OP_lit21";
+ return DW_DLV_OK;
+ case DW_OP_lit22:
+ *s_out = "DW_OP_lit22";
+ return DW_DLV_OK;
+ case DW_OP_lit23:
+ *s_out = "DW_OP_lit23";
+ return DW_DLV_OK;
+ case DW_OP_lit24:
+ *s_out = "DW_OP_lit24";
+ return DW_DLV_OK;
+ case DW_OP_lit25:
+ *s_out = "DW_OP_lit25";
+ return DW_DLV_OK;
+ case DW_OP_lit26:
+ *s_out = "DW_OP_lit26";
+ return DW_DLV_OK;
+ case DW_OP_lit27:
+ *s_out = "DW_OP_lit27";
+ return DW_DLV_OK;
+ case DW_OP_lit28:
+ *s_out = "DW_OP_lit28";
+ return DW_DLV_OK;
+ case DW_OP_lit29:
+ *s_out = "DW_OP_lit29";
+ return DW_DLV_OK;
+ case DW_OP_lit30:
+ *s_out = "DW_OP_lit30";
+ return DW_DLV_OK;
+ case DW_OP_lit31:
+ *s_out = "DW_OP_lit31";
+ return DW_DLV_OK;
+ case DW_OP_reg0:
+ *s_out = "DW_OP_reg0";
+ return DW_DLV_OK;
+ case DW_OP_reg1:
+ *s_out = "DW_OP_reg1";
+ return DW_DLV_OK;
+ case DW_OP_reg2:
+ *s_out = "DW_OP_reg2";
+ return DW_DLV_OK;
+ case DW_OP_reg3:
+ *s_out = "DW_OP_reg3";
+ return DW_DLV_OK;
+ case DW_OP_reg4:
+ *s_out = "DW_OP_reg4";
+ return DW_DLV_OK;
+ case DW_OP_reg5:
+ *s_out = "DW_OP_reg5";
+ return DW_DLV_OK;
+ case DW_OP_reg6:
+ *s_out = "DW_OP_reg6";
+ return DW_DLV_OK;
+ case DW_OP_reg7:
+ *s_out = "DW_OP_reg7";
+ return DW_DLV_OK;
+ case DW_OP_reg8:
+ *s_out = "DW_OP_reg8";
+ return DW_DLV_OK;
+ case DW_OP_reg9:
+ *s_out = "DW_OP_reg9";
+ return DW_DLV_OK;
+ case DW_OP_reg10:
+ *s_out = "DW_OP_reg10";
+ return DW_DLV_OK;
+ case DW_OP_reg11:
+ *s_out = "DW_OP_reg11";
+ return DW_DLV_OK;
+ case DW_OP_reg12:
+ *s_out = "DW_OP_reg12";
+ return DW_DLV_OK;
+ case DW_OP_reg13:
+ *s_out = "DW_OP_reg13";
+ return DW_DLV_OK;
+ case DW_OP_reg14:
+ *s_out = "DW_OP_reg14";
+ return DW_DLV_OK;
+ case DW_OP_reg15:
+ *s_out = "DW_OP_reg15";
+ return DW_DLV_OK;
+ case DW_OP_reg16:
+ *s_out = "DW_OP_reg16";
+ return DW_DLV_OK;
+ case DW_OP_reg17:
+ *s_out = "DW_OP_reg17";
+ return DW_DLV_OK;
+ case DW_OP_reg18:
+ *s_out = "DW_OP_reg18";
+ return DW_DLV_OK;
+ case DW_OP_reg19:
+ *s_out = "DW_OP_reg19";
+ return DW_DLV_OK;
+ case DW_OP_reg20:
+ *s_out = "DW_OP_reg20";
+ return DW_DLV_OK;
+ case DW_OP_reg21:
+ *s_out = "DW_OP_reg21";
+ return DW_DLV_OK;
+ case DW_OP_reg22:
+ *s_out = "DW_OP_reg22";
+ return DW_DLV_OK;
+ case DW_OP_reg23:
+ *s_out = "DW_OP_reg23";
+ return DW_DLV_OK;
+ case DW_OP_reg24:
+ *s_out = "DW_OP_reg24";
+ return DW_DLV_OK;
+ case DW_OP_reg25:
+ *s_out = "DW_OP_reg25";
+ return DW_DLV_OK;
+ case DW_OP_reg26:
+ *s_out = "DW_OP_reg26";
+ return DW_DLV_OK;
+ case DW_OP_reg27:
+ *s_out = "DW_OP_reg27";
+ return DW_DLV_OK;
+ case DW_OP_reg28:
+ *s_out = "DW_OP_reg28";
+ return DW_DLV_OK;
+ case DW_OP_reg29:
+ *s_out = "DW_OP_reg29";
+ return DW_DLV_OK;
+ case DW_OP_reg30:
+ *s_out = "DW_OP_reg30";
+ return DW_DLV_OK;
+ case DW_OP_reg31:
+ *s_out = "DW_OP_reg31";
+ return DW_DLV_OK;
+ case DW_OP_breg0:
+ *s_out = "DW_OP_breg0";
+ return DW_DLV_OK;
+ case DW_OP_breg1:
+ *s_out = "DW_OP_breg1";
+ return DW_DLV_OK;
+ case DW_OP_breg2:
+ *s_out = "DW_OP_breg2";
+ return DW_DLV_OK;
+ case DW_OP_breg3:
+ *s_out = "DW_OP_breg3";
+ return DW_DLV_OK;
+ case DW_OP_breg4:
+ *s_out = "DW_OP_breg4";
+ return DW_DLV_OK;
+ case DW_OP_breg5:
+ *s_out = "DW_OP_breg5";
+ return DW_DLV_OK;
+ case DW_OP_breg6:
+ *s_out = "DW_OP_breg6";
+ return DW_DLV_OK;
+ case DW_OP_breg7:
+ *s_out = "DW_OP_breg7";
+ return DW_DLV_OK;
+ case DW_OP_breg8:
+ *s_out = "DW_OP_breg8";
+ return DW_DLV_OK;
+ case DW_OP_breg9:
+ *s_out = "DW_OP_breg9";
+ return DW_DLV_OK;
+ case DW_OP_breg10:
+ *s_out = "DW_OP_breg10";
+ return DW_DLV_OK;
+ case DW_OP_breg11:
+ *s_out = "DW_OP_breg11";
+ return DW_DLV_OK;
+ case DW_OP_breg12:
+ *s_out = "DW_OP_breg12";
+ return DW_DLV_OK;
+ case DW_OP_breg13:
+ *s_out = "DW_OP_breg13";
+ return DW_DLV_OK;
+ case DW_OP_breg14:
+ *s_out = "DW_OP_breg14";
+ return DW_DLV_OK;
+ case DW_OP_breg15:
+ *s_out = "DW_OP_breg15";
+ return DW_DLV_OK;
+ case DW_OP_breg16:
+ *s_out = "DW_OP_breg16";
+ return DW_DLV_OK;
+ case DW_OP_breg17:
+ *s_out = "DW_OP_breg17";
+ return DW_DLV_OK;
+ case DW_OP_breg18:
+ *s_out = "DW_OP_breg18";
+ return DW_DLV_OK;
+ case DW_OP_breg19:
+ *s_out = "DW_OP_breg19";
+ return DW_DLV_OK;
+ case DW_OP_breg20:
+ *s_out = "DW_OP_breg20";
+ return DW_DLV_OK;
+ case DW_OP_breg21:
+ *s_out = "DW_OP_breg21";
+ return DW_DLV_OK;
+ case DW_OP_breg22:
+ *s_out = "DW_OP_breg22";
+ return DW_DLV_OK;
+ case DW_OP_breg23:
+ *s_out = "DW_OP_breg23";
+ return DW_DLV_OK;
+ case DW_OP_breg24:
+ *s_out = "DW_OP_breg24";
+ return DW_DLV_OK;
+ case DW_OP_breg25:
+ *s_out = "DW_OP_breg25";
+ return DW_DLV_OK;
+ case DW_OP_breg26:
+ *s_out = "DW_OP_breg26";
+ return DW_DLV_OK;
+ case DW_OP_breg27:
+ *s_out = "DW_OP_breg27";
+ return DW_DLV_OK;
+ case DW_OP_breg28:
+ *s_out = "DW_OP_breg28";
+ return DW_DLV_OK;
+ case DW_OP_breg29:
+ *s_out = "DW_OP_breg29";
+ return DW_DLV_OK;
+ case DW_OP_breg30:
+ *s_out = "DW_OP_breg30";
+ return DW_DLV_OK;
+ case DW_OP_breg31:
+ *s_out = "DW_OP_breg31";
+ return DW_DLV_OK;
+ case DW_OP_regx:
+ *s_out = "DW_OP_regx";
+ return DW_DLV_OK;
+ case DW_OP_fbreg:
+ *s_out = "DW_OP_fbreg";
+ return DW_DLV_OK;
+ case DW_OP_bregx:
+ *s_out = "DW_OP_bregx";
+ return DW_DLV_OK;
+ case DW_OP_piece:
+ *s_out = "DW_OP_piece";
+ return DW_DLV_OK;
+ case DW_OP_deref_size:
+ *s_out = "DW_OP_deref_size";
+ return DW_DLV_OK;
+ case DW_OP_xderef_size:
+ *s_out = "DW_OP_xderef_size";
+ return DW_DLV_OK;
+ case DW_OP_nop:
+ *s_out = "DW_OP_nop";
+ return DW_DLV_OK;
+ case DW_OP_push_object_address:
+ *s_out = "DW_OP_push_object_address";
+ return DW_DLV_OK;
+ case DW_OP_call2:
+ *s_out = "DW_OP_call2";
+ return DW_DLV_OK;
+ case DW_OP_call4:
+ *s_out = "DW_OP_call4";
+ return DW_DLV_OK;
+ case DW_OP_call_ref:
+ *s_out = "DW_OP_call_ref";
+ return DW_DLV_OK;
+ case DW_OP_form_tls_address:
+ *s_out = "DW_OP_form_tls_address";
+ return DW_DLV_OK;
+ case DW_OP_call_frame_cfa:
+ *s_out = "DW_OP_call_frame_cfa";
+ return DW_DLV_OK;
+ case DW_OP_bit_piece:
+ *s_out = "DW_OP_bit_piece";
+ return DW_DLV_OK;
+ case DW_OP_implicit_value:
+ *s_out = "DW_OP_implicit_value";
+ return DW_DLV_OK;
+ case DW_OP_stack_value:
+ *s_out = "DW_OP_stack_value";
+ return DW_DLV_OK;
+ case DW_OP_lo_user:
+ *s_out = "DW_OP_lo_user";
+ return DW_DLV_OK;
+ case DW_OP_HP_is_value:
+ *s_out = "DW_OP_HP_is_value";
+ return DW_DLV_OK;
+ case DW_OP_HP_fltconst4:
+ *s_out = "DW_OP_HP_fltconst4";
+ return DW_DLV_OK;
+ case DW_OP_HP_fltconst8:
+ *s_out = "DW_OP_HP_fltconst8";
+ return DW_DLV_OK;
+ case DW_OP_HP_mod_range:
+ *s_out = "DW_OP_HP_mod_range";
+ return DW_DLV_OK;
+ case DW_OP_HP_unmod_range:
+ *s_out = "DW_OP_HP_unmod_range";
+ return DW_DLV_OK;
+ case DW_OP_HP_tls:
+ *s_out = "DW_OP_HP_tls";
+ return DW_DLV_OK;
+ case DW_OP_INTEL_bit_piece:
+ *s_out = "DW_OP_INTEL_bit_piece";
+ return DW_DLV_OK;
+ case DW_OP_APPLE_uninit:
+ *s_out = "DW_OP_APPLE_uninit";
+ return DW_DLV_OK;
+ case DW_OP_hi_user:
+ *s_out = "DW_OP_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ATE_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ATE_address:
+ *s_out = "DW_ATE_address";
+ return DW_DLV_OK;
+ case DW_ATE_boolean:
+ *s_out = "DW_ATE_boolean";
+ return DW_DLV_OK;
+ case DW_ATE_complex_float:
+ *s_out = "DW_ATE_complex_float";
+ return DW_DLV_OK;
+ case DW_ATE_float:
+ *s_out = "DW_ATE_float";
+ return DW_DLV_OK;
+ case DW_ATE_signed:
+ *s_out = "DW_ATE_signed";
+ return DW_DLV_OK;
+ case DW_ATE_signed_char:
+ *s_out = "DW_ATE_signed_char";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned:
+ *s_out = "DW_ATE_unsigned";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned_char:
+ *s_out = "DW_ATE_unsigned_char";
+ return DW_DLV_OK;
+ case DW_ATE_imaginary_float:
+ *s_out = "DW_ATE_imaginary_float";
+ return DW_DLV_OK;
+ case DW_ATE_packed_decimal:
+ *s_out = "DW_ATE_packed_decimal";
+ return DW_DLV_OK;
+ case DW_ATE_numeric_string:
+ *s_out = "DW_ATE_numeric_string";
+ return DW_DLV_OK;
+ case DW_ATE_edited:
+ *s_out = "DW_ATE_edited";
+ return DW_DLV_OK;
+ case DW_ATE_signed_fixed:
+ *s_out = "DW_ATE_signed_fixed";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned_fixed:
+ *s_out = "DW_ATE_unsigned_fixed";
+ return DW_DLV_OK;
+ case DW_ATE_decimal_float:
+ *s_out = "DW_ATE_decimal_float";
+ return DW_DLV_OK;
+ case DW_ATE_HP_float80:
+ *s_out = "DW_ATE_HP_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_complex_float80:
+ *s_out = "DW_ATE_HP_complex_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_float128:
+ *s_out = "DW_ATE_HP_float128";
+ return DW_DLV_OK;
+ case DW_ATE_HP_complex_float128:
+ *s_out = "DW_ATE_HP_complex_float128";
+ return DW_DLV_OK;
+ case DW_ATE_HP_floathpintel:
+ *s_out = "DW_ATE_HP_floathpintel";
+ return DW_DLV_OK;
+ case DW_ATE_HP_imaginary_float80:
+ *s_out = "DW_ATE_HP_imaginary_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_imaginary_float128:
+ *s_out = "DW_ATE_HP_imaginary_float128";
+ return DW_DLV_OK;
+ case DW_ATE_SUN_interval_float:
+ *s_out = "DW_ATE_SUN_interval_float";
+ return DW_DLV_OK;
+ case DW_ATE_SUN_imaginary_float:
+ *s_out = "DW_ATE_SUN_imaginary_float";
+ return DW_DLV_OK;
+ case DW_ATE_hi_user:
+ *s_out = "DW_ATE_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_DS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_DS_unsigned:
+ *s_out = "DW_DS_unsigned";
+ return DW_DLV_OK;
+ case DW_DS_leading_overpunch:
+ *s_out = "DW_DS_leading_overpunch";
+ return DW_DLV_OK;
+ case DW_DS_trailing_overpunch:
+ *s_out = "DW_DS_trailing_overpunch";
+ return DW_DLV_OK;
+ case DW_DS_leading_separate:
+ *s_out = "DW_DS_leading_separate";
+ return DW_DLV_OK;
+ case DW_DS_trailing_separate:
+ *s_out = "DW_DS_trailing_separate";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_END_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_END_default:
+ *s_out = "DW_END_default";
+ return DW_DLV_OK;
+ case DW_END_big:
+ *s_out = "DW_END_big";
+ return DW_DLV_OK;
+ case DW_END_little:
+ *s_out = "DW_END_little";
+ return DW_DLV_OK;
+ case DW_END_lo_user:
+ *s_out = "DW_END_lo_user";
+ return DW_DLV_OK;
+ case DW_END_hi_user:
+ *s_out = "DW_END_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ATCF_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ATCF_lo_user:
+ *s_out = "DW_ATCF_lo_user";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_bitfield:
+ *s_out = "DW_ATCF_SUN_mop_bitfield";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_spill:
+ *s_out = "DW_ATCF_SUN_mop_spill";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_scopy:
+ *s_out = "DW_ATCF_SUN_mop_scopy";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_func_start:
+ *s_out = "DW_ATCF_SUN_func_start";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_end_ctors:
+ *s_out = "DW_ATCF_SUN_end_ctors";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_branch_target:
+ *s_out = "DW_ATCF_SUN_branch_target";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_stack_probe:
+ *s_out = "DW_ATCF_SUN_mop_stack_probe";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_func_epilog:
+ *s_out = "DW_ATCF_SUN_func_epilog";
+ return DW_DLV_OK;
+ case DW_ATCF_hi_user:
+ *s_out = "DW_ATCF_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ACCESS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ACCESS_public:
+ *s_out = "DW_ACCESS_public";
+ return DW_DLV_OK;
+ case DW_ACCESS_protected:
+ *s_out = "DW_ACCESS_protected";
+ return DW_DLV_OK;
+ case DW_ACCESS_private:
+ *s_out = "DW_ACCESS_private";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_VIS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_VIS_local:
+ *s_out = "DW_VIS_local";
+ return DW_DLV_OK;
+ case DW_VIS_exported:
+ *s_out = "DW_VIS_exported";
+ return DW_DLV_OK;
+ case DW_VIS_qualified:
+ *s_out = "DW_VIS_qualified";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_VIRTUALITY_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_VIRTUALITY_none:
+ *s_out = "DW_VIRTUALITY_none";
+ return DW_DLV_OK;
+ case DW_VIRTUALITY_virtual:
+ *s_out = "DW_VIRTUALITY_virtual";
+ return DW_DLV_OK;
+ case DW_VIRTUALITY_pure_virtual:
+ *s_out = "DW_VIRTUALITY_pure_virtual";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LANG_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LANG_C89:
+ *s_out = "DW_LANG_C89";
+ return DW_DLV_OK;
+ case DW_LANG_C:
+ *s_out = "DW_LANG_C";
+ return DW_DLV_OK;
+ case DW_LANG_Ada83:
+ *s_out = "DW_LANG_Ada83";
+ return DW_DLV_OK;
+ case DW_LANG_C_plus_plus:
+ *s_out = "DW_LANG_C_plus_plus";
+ return DW_DLV_OK;
+ case DW_LANG_Cobol74:
+ *s_out = "DW_LANG_Cobol74";
+ return DW_DLV_OK;
+ case DW_LANG_Cobol85:
+ *s_out = "DW_LANG_Cobol85";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran77:
+ *s_out = "DW_LANG_Fortran77";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran90:
+ *s_out = "DW_LANG_Fortran90";
+ return DW_DLV_OK;
+ case DW_LANG_Pascal83:
+ *s_out = "DW_LANG_Pascal83";
+ return DW_DLV_OK;
+ case DW_LANG_Modula2:
+ *s_out = "DW_LANG_Modula2";
+ return DW_DLV_OK;
+ case DW_LANG_Java:
+ *s_out = "DW_LANG_Java";
+ return DW_DLV_OK;
+ case DW_LANG_C99:
+ *s_out = "DW_LANG_C99";
+ return DW_DLV_OK;
+ case DW_LANG_Ada95:
+ *s_out = "DW_LANG_Ada95";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran95:
+ *s_out = "DW_LANG_Fortran95";
+ return DW_DLV_OK;
+ case DW_LANG_PLI:
+ *s_out = "DW_LANG_PLI";
+ return DW_DLV_OK;
+ case DW_LANG_ObjC:
+ *s_out = "DW_LANG_ObjC";
+ return DW_DLV_OK;
+ case DW_LANG_ObjC_plus_plus:
+ *s_out = "DW_LANG_ObjC_plus_plus";
+ return DW_DLV_OK;
+ case DW_LANG_UPC:
+ *s_out = "DW_LANG_UPC";
+ return DW_DLV_OK;
+ case DW_LANG_D:
+ *s_out = "DW_LANG_D";
+ return DW_DLV_OK;
+ case DW_LANG_Python:
+ *s_out = "DW_LANG_Python";
+ return DW_DLV_OK;
+ case DW_LANG_OpenCL:
+ *s_out = "DW_LANG_OpenCL";
+ return DW_DLV_OK;
+ case DW_LANG_Go:
+ *s_out = "DW_LANG_Go";
+ return DW_DLV_OK;
+ case DW_LANG_lo_user:
+ *s_out = "DW_LANG_lo_user";
+ return DW_DLV_OK;
+ case DW_LANG_Mips_Assembler:
+ *s_out = "DW_LANG_Mips_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_Upc:
+ *s_out = "DW_LANG_Upc";
+ return DW_DLV_OK;
+ case DW_LANG_SUN_Assembler:
+ *s_out = "DW_LANG_SUN_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_ALTIUM_Assembler:
+ *s_out = "DW_LANG_ALTIUM_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_hi_user:
+ *s_out = "DW_LANG_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ID_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ID_case_sensitive:
+ *s_out = "DW_ID_case_sensitive";
+ return DW_DLV_OK;
+ case DW_ID_up_case:
+ *s_out = "DW_ID_up_case";
+ return DW_DLV_OK;
+ case DW_ID_down_case:
+ *s_out = "DW_ID_down_case";
+ return DW_DLV_OK;
+ case DW_ID_case_insensitive:
+ *s_out = "DW_ID_case_insensitive";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CC_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CC_normal:
+ *s_out = "DW_CC_normal";
+ return DW_DLV_OK;
+ case DW_CC_program:
+ *s_out = "DW_CC_program";
+ return DW_DLV_OK;
+ case DW_CC_nocall:
+ *s_out = "DW_CC_nocall";
+ return DW_DLV_OK;
+ case DW_CC_lo_user:
+ *s_out = "DW_CC_lo_user";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_interrupt:
+ *s_out = "DW_CC_ALTIUM_interrupt";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_near_system_stack:
+ *s_out = "DW_CC_ALTIUM_near_system_stack";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_near_user_stack:
+ *s_out = "DW_CC_ALTIUM_near_user_stack";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_huge_user_stack:
+ *s_out = "DW_CC_ALTIUM_huge_user_stack";
+ return DW_DLV_OK;
+ case DW_CC_hi_user:
+ *s_out = "DW_CC_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_INL_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_INL_not_inlined:
+ *s_out = "DW_INL_not_inlined";
+ return DW_DLV_OK;
+ case DW_INL_inlined:
+ *s_out = "DW_INL_inlined";
+ return DW_DLV_OK;
+ case DW_INL_declared_not_inlined:
+ *s_out = "DW_INL_declared_not_inlined";
+ return DW_DLV_OK;
+ case DW_INL_declared_inlined:
+ *s_out = "DW_INL_declared_inlined";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ORD_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ORD_row_major:
+ *s_out = "DW_ORD_row_major";
+ return DW_DLV_OK;
+ case DW_ORD_col_major:
+ *s_out = "DW_ORD_col_major";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_DSC_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_DSC_label:
+ *s_out = "DW_DSC_label";
+ return DW_DLV_OK;
+ case DW_DSC_range:
+ *s_out = "DW_DSC_range";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LNS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LNS_copy:
+ *s_out = "DW_LNS_copy";
+ return DW_DLV_OK;
+ case DW_LNS_advance_pc:
+ *s_out = "DW_LNS_advance_pc";
+ return DW_DLV_OK;
+ case DW_LNS_advance_line:
+ *s_out = "DW_LNS_advance_line";
+ return DW_DLV_OK;
+ case DW_LNS_set_file:
+ *s_out = "DW_LNS_set_file";
+ return DW_DLV_OK;
+ case DW_LNS_set_column:
+ *s_out = "DW_LNS_set_column";
+ return DW_DLV_OK;
+ case DW_LNS_negate_stmt:
+ *s_out = "DW_LNS_negate_stmt";
+ return DW_DLV_OK;
+ case DW_LNS_set_basic_block:
+ *s_out = "DW_LNS_set_basic_block";
+ return DW_DLV_OK;
+ case DW_LNS_const_add_pc:
+ *s_out = "DW_LNS_const_add_pc";
+ return DW_DLV_OK;
+ case DW_LNS_fixed_advance_pc:
+ *s_out = "DW_LNS_fixed_advance_pc";
+ return DW_DLV_OK;
+ case DW_LNS_set_prologue_end:
+ *s_out = "DW_LNS_set_prologue_end";
+ return DW_DLV_OK;
+ case DW_LNS_set_epilogue_begin:
+ *s_out = "DW_LNS_set_epilogue_begin";
+ return DW_DLV_OK;
+ case DW_LNS_set_isa:
+ *s_out = "DW_LNS_set_isa";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LNE_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LNE_end_sequence:
+ *s_out = "DW_LNE_end_sequence";
+ return DW_DLV_OK;
+ case DW_LNE_set_address:
+ *s_out = "DW_LNE_set_address";
+ return DW_DLV_OK;
+ case DW_LNE_define_file:
+ *s_out = "DW_LNE_define_file";
+ return DW_DLV_OK;
+ case DW_LNE_set_discriminator:
+ *s_out = "DW_LNE_set_discriminator";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_is_UV_update:
+ *s_out = "DW_LNE_HP_negate_is_UV_update";
+ return DW_DLV_OK;
+ case DW_LNE_HP_push_context:
+ *s_out = "DW_LNE_HP_push_context";
+ return DW_DLV_OK;
+ case DW_LNE_HP_pop_context:
+ *s_out = "DW_LNE_HP_pop_context";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_file_line_column:
+ *s_out = "DW_LNE_HP_set_file_line_column";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_routine_name:
+ *s_out = "DW_LNE_HP_set_routine_name";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_sequence:
+ *s_out = "DW_LNE_HP_set_sequence";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_post_semantics:
+ *s_out = "DW_LNE_HP_negate_post_semantics";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_function_exit:
+ *s_out = "DW_LNE_HP_negate_function_exit";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_front_end_logical:
+ *s_out = "DW_LNE_HP_negate_front_end_logical";
+ return DW_DLV_OK;
+ case DW_LNE_HP_define_proc:
+ *s_out = "DW_LNE_HP_define_proc";
+ return DW_DLV_OK;
+ case DW_LNE_lo_user:
+ *s_out = "DW_LNE_lo_user";
+ return DW_DLV_OK;
+ case DW_LNE_hi_user:
+ *s_out = "DW_LNE_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ISA_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ISA_UNKNOWN:
+ *s_out = "DW_ISA_UNKNOWN";
+ return DW_DLV_OK;
+ case DW_ISA_ARM_thumb:
+ *s_out = "DW_ISA_ARM_thumb";
+ return DW_DLV_OK;
+ case DW_ISA_ARM_arm:
+ *s_out = "DW_ISA_ARM_arm";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_MACINFO_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_MACINFO_define:
+ *s_out = "DW_MACINFO_define";
+ return DW_DLV_OK;
+ case DW_MACINFO_undef:
+ *s_out = "DW_MACINFO_undef";
+ return DW_DLV_OK;
+ case DW_MACINFO_start_file:
+ *s_out = "DW_MACINFO_start_file";
+ return DW_DLV_OK;
+ case DW_MACINFO_end_file:
+ *s_out = "DW_MACINFO_end_file";
+ return DW_DLV_OK;
+ case DW_MACINFO_vendor_ext:
+ *s_out = "DW_MACINFO_vendor_ext";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CFA_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CFA_extended:
+ *s_out = "DW_CFA_extended";
+ return DW_DLV_OK;
+ case DW_CFA_set_loc:
+ *s_out = "DW_CFA_set_loc";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc1:
+ *s_out = "DW_CFA_advance_loc1";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc2:
+ *s_out = "DW_CFA_advance_loc2";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc4:
+ *s_out = "DW_CFA_advance_loc4";
+ return DW_DLV_OK;
+ case DW_CFA_offset_extended:
+ *s_out = "DW_CFA_offset_extended";
+ return DW_DLV_OK;
+ case DW_CFA_restore_extended:
+ *s_out = "DW_CFA_restore_extended";
+ return DW_DLV_OK;
+ case DW_CFA_undefined:
+ *s_out = "DW_CFA_undefined";
+ return DW_DLV_OK;
+ case DW_CFA_same_value:
+ *s_out = "DW_CFA_same_value";
+ return DW_DLV_OK;
+ case DW_CFA_register:
+ *s_out = "DW_CFA_register";
+ return DW_DLV_OK;
+ case DW_CFA_remember_state:
+ *s_out = "DW_CFA_remember_state";
+ return DW_DLV_OK;
+ case DW_CFA_restore_state:
+ *s_out = "DW_CFA_restore_state";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa:
+ *s_out = "DW_CFA_def_cfa";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_register:
+ *s_out = "DW_CFA_def_cfa_register";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_offset:
+ *s_out = "DW_CFA_def_cfa_offset";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_expression:
+ *s_out = "DW_CFA_def_cfa_expression";
+ return DW_DLV_OK;
+ case DW_CFA_expression:
+ *s_out = "DW_CFA_expression";
+ return DW_DLV_OK;
+ case DW_CFA_offset_extended_sf:
+ *s_out = "DW_CFA_offset_extended_sf";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_sf:
+ *s_out = "DW_CFA_def_cfa_sf";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_offset_sf:
+ *s_out = "DW_CFA_def_cfa_offset_sf";
+ return DW_DLV_OK;
+ case DW_CFA_val_offset:
+ *s_out = "DW_CFA_val_offset";
+ return DW_DLV_OK;
+ case DW_CFA_val_offset_sf:
+ *s_out = "DW_CFA_val_offset_sf";
+ return DW_DLV_OK;
+ case DW_CFA_val_expression:
+ *s_out = "DW_CFA_val_expression";
+ return DW_DLV_OK;
+ case DW_CFA_lo_user:
+ *s_out = "DW_CFA_lo_user";
+ return DW_DLV_OK;
+ case DW_CFA_MIPS_advance_loc8:
+ *s_out = "DW_CFA_MIPS_advance_loc8";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_window_save:
+ *s_out = "DW_CFA_GNU_window_save";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_args_size:
+ *s_out = "DW_CFA_GNU_args_size";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_negative_offset_extended:
+ *s_out = "DW_CFA_GNU_negative_offset_extended";
+ return DW_DLV_OK;
+ case DW_CFA_high_user:
+ *s_out = "DW_CFA_high_user";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc:
+ *s_out = "DW_CFA_advance_loc";
+ return DW_DLV_OK;
+ case DW_CFA_offset:
+ *s_out = "DW_CFA_offset";
+ return DW_DLV_OK;
+ case DW_CFA_restore:
+ *s_out = "DW_CFA_restore";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_EH_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_EH_PE_absptr:
+ *s_out = "DW_EH_PE_absptr";
+ return DW_DLV_OK;
+ case DW_EH_PE_uleb128:
+ *s_out = "DW_EH_PE_uleb128";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata2:
+ *s_out = "DW_EH_PE_udata2";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata4:
+ *s_out = "DW_EH_PE_udata4";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata8:
+ *s_out = "DW_EH_PE_udata8";
+ return DW_DLV_OK;
+ case DW_EH_PE_sleb128:
+ *s_out = "DW_EH_PE_sleb128";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata2:
+ *s_out = "DW_EH_PE_sdata2";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata4:
+ *s_out = "DW_EH_PE_sdata4";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata8:
+ *s_out = "DW_EH_PE_sdata8";
+ return DW_DLV_OK;
+ case DW_EH_PE_pcrel:
+ *s_out = "DW_EH_PE_pcrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_textrel:
+ *s_out = "DW_EH_PE_textrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_datarel:
+ *s_out = "DW_EH_PE_datarel";
+ return DW_DLV_OK;
+ case DW_EH_PE_funcrel:
+ *s_out = "DW_EH_PE_funcrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_aligned:
+ *s_out = "DW_EH_PE_aligned";
+ return DW_DLV_OK;
+ case DW_EH_PE_omit:
+ *s_out = "DW_EH_PE_omit";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_FRAME_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_FRAME_CFA_COL:
+ *s_out = "DW_FRAME_CFA_COL";
+ return DW_DLV_OK;
+ case DW_FRAME_REG1:
+ *s_out = "DW_FRAME_REG1";
+ return DW_DLV_OK;
+ case DW_FRAME_REG2:
+ *s_out = "DW_FRAME_REG2";
+ return DW_DLV_OK;
+ case DW_FRAME_REG3:
+ *s_out = "DW_FRAME_REG3";
+ return DW_DLV_OK;
+ case DW_FRAME_REG4:
+ *s_out = "DW_FRAME_REG4";
+ return DW_DLV_OK;
+ case DW_FRAME_REG5:
+ *s_out = "DW_FRAME_REG5";
+ return DW_DLV_OK;
+ case DW_FRAME_REG6:
+ *s_out = "DW_FRAME_REG6";
+ return DW_DLV_OK;
+ case DW_FRAME_REG7:
+ *s_out = "DW_FRAME_REG7";
+ return DW_DLV_OK;
+ case DW_FRAME_REG8:
+ *s_out = "DW_FRAME_REG8";
+ return DW_DLV_OK;
+ case DW_FRAME_REG9:
+ *s_out = "DW_FRAME_REG9";
+ return DW_DLV_OK;
+ case DW_FRAME_REG10:
+ *s_out = "DW_FRAME_REG10";
+ return DW_DLV_OK;
+ case DW_FRAME_REG11:
+ *s_out = "DW_FRAME_REG11";
+ return DW_DLV_OK;
+ case DW_FRAME_REG12:
+ *s_out = "DW_FRAME_REG12";
+ return DW_DLV_OK;
+ case DW_FRAME_REG13:
+ *s_out = "DW_FRAME_REG13";
+ return DW_DLV_OK;
+ case DW_FRAME_REG14:
+ *s_out = "DW_FRAME_REG14";
+ return DW_DLV_OK;
+ case DW_FRAME_REG15:
+ *s_out = "DW_FRAME_REG15";
+ return DW_DLV_OK;
+ case DW_FRAME_REG16:
+ *s_out = "DW_FRAME_REG16";
+ return DW_DLV_OK;
+ case DW_FRAME_REG17:
+ *s_out = "DW_FRAME_REG17";
+ return DW_DLV_OK;
+ case DW_FRAME_REG18:
+ *s_out = "DW_FRAME_REG18";
+ return DW_DLV_OK;
+ case DW_FRAME_REG19:
+ *s_out = "DW_FRAME_REG19";
+ return DW_DLV_OK;
+ case DW_FRAME_REG20:
+ *s_out = "DW_FRAME_REG20";
+ return DW_DLV_OK;
+ case DW_FRAME_REG21:
+ *s_out = "DW_FRAME_REG21";
+ return DW_DLV_OK;
+ case DW_FRAME_REG22:
+ *s_out = "DW_FRAME_REG22";
+ return DW_DLV_OK;
+ case DW_FRAME_REG23:
+ *s_out = "DW_FRAME_REG23";
+ return DW_DLV_OK;
+ case DW_FRAME_REG24:
+ *s_out = "DW_FRAME_REG24";
+ return DW_DLV_OK;
+ case DW_FRAME_REG25:
+ *s_out = "DW_FRAME_REG25";
+ return DW_DLV_OK;
+ case DW_FRAME_REG26:
+ *s_out = "DW_FRAME_REG26";
+ return DW_DLV_OK;
+ case DW_FRAME_REG27:
+ *s_out = "DW_FRAME_REG27";
+ return DW_DLV_OK;
+ case DW_FRAME_REG28:
+ *s_out = "DW_FRAME_REG28";
+ return DW_DLV_OK;
+ case DW_FRAME_REG29:
+ *s_out = "DW_FRAME_REG29";
+ return DW_DLV_OK;
+ case DW_FRAME_REG30:
+ *s_out = "DW_FRAME_REG30";
+ return DW_DLV_OK;
+ case DW_FRAME_REG31:
+ *s_out = "DW_FRAME_REG31";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG0:
+ *s_out = "DW_FRAME_FREG0";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG1:
+ *s_out = "DW_FRAME_FREG1";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG2:
+ *s_out = "DW_FRAME_FREG2";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG3:
+ *s_out = "DW_FRAME_FREG3";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG4:
+ *s_out = "DW_FRAME_FREG4";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG5:
+ *s_out = "DW_FRAME_FREG5";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG6:
+ *s_out = "DW_FRAME_FREG6";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG7:
+ *s_out = "DW_FRAME_FREG7";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG8:
+ *s_out = "DW_FRAME_FREG8";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG9:
+ *s_out = "DW_FRAME_FREG9";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG10:
+ *s_out = "DW_FRAME_FREG10";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG11:
+ *s_out = "DW_FRAME_FREG11";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG12:
+ *s_out = "DW_FRAME_FREG12";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG13:
+ *s_out = "DW_FRAME_FREG13";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG14:
+ *s_out = "DW_FRAME_FREG14";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG15:
+ *s_out = "DW_FRAME_FREG15";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG16:
+ *s_out = "DW_FRAME_FREG16";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG17:
+ *s_out = "DW_FRAME_FREG17";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG18:
+ *s_out = "DW_FRAME_FREG18";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG19:
+ *s_out = "DW_FRAME_FREG19";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG20:
+ *s_out = "DW_FRAME_FREG20";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG21:
+ *s_out = "DW_FRAME_FREG21";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG22:
+ *s_out = "DW_FRAME_FREG22";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG23:
+ *s_out = "DW_FRAME_FREG23";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG24:
+ *s_out = "DW_FRAME_FREG24";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG25:
+ *s_out = "DW_FRAME_FREG25";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG26:
+ *s_out = "DW_FRAME_FREG26";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG27:
+ *s_out = "DW_FRAME_FREG27";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG28:
+ *s_out = "DW_FRAME_FREG28";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG29:
+ *s_out = "DW_FRAME_FREG29";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG30:
+ *s_out = "DW_FRAME_FREG30";
+ return DW_DLV_OK;
+ case DW_FRAME_HIGHEST_NORMAL_REGISTER:
+ *s_out = "DW_FRAME_HIGHEST_NORMAL_REGISTER";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CHILDREN_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CHILDREN_no:
+ *s_out = "DW_CHILDREN_no";
+ return DW_DLV_OK;
+ case DW_CHILDREN_yes:
+ *s_out = "DW_CHILDREN_yes";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ADDR_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ADDR_none:
+ *s_out = "DW_ADDR_none";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+/* END FILE */
diff --git a/usr/src/lib/libdwarf/common/dwarf_names.h b/usr/src/lib/libdwarf/common/dwarf_names.h
new file mode 100644
index 0000000000..6edafa5fdd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_names.h
@@ -0,0 +1,34 @@
+/* Generated routines, do not edit. */
+/* Generated on May 22 2011 03:05:33 */
+
+/* BEGIN FILE */
+
+extern int dwarf_get_TAG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_children_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FORM_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_AT_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_OP_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_END_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATCF_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ACCESS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIRTUALITY_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LANG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ID_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_INL_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ORD_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DSC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ISA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_MACINFO_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CFA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_EH_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FRAME_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CHILDREN_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ADDR_name(unsigned int /*val_in*/, const char ** /*s_out */);
+
+/* END FILE */
diff --git a/usr/src/lib/libdwarf/common/dwarf_opaque.h b/usr/src/lib/libdwarf/common/dwarf_opaque.h
new file mode 100644
index 0000000000..b235a9c7b4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_opaque.h
@@ -0,0 +1,339 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The versions applicable by section are:
+ DWARF2 DWARF3 DWARF4
+ .debug_abbrev - - -
+ .debug_aranges 2 2 2
+ .debug_frame 1 3 4
+ .debug_info 2 3 4
+ .debug_line 2 3 4
+ .debug_loc - - -
+ .debug_macinfo - - -
+ .debug_pubtypes x 2 2
+ .debug_pubnames 2 2 2
+ .debug_ranges x - -
+ .debug_str - - -
+ .debug_types x x 4
+*/
+
+#include <stddef.h>
+
+
+struct Dwarf_Die_s {
+ Dwarf_Byte_Ptr di_debug_info_ptr;
+ Dwarf_Abbrev_List di_abbrev_list;
+ Dwarf_CU_Context di_cu_context;
+ int di_abbrev_code;
+};
+
+struct Dwarf_Attribute_s {
+ Dwarf_Half ar_attribute; /* Attribute Value. */
+ Dwarf_Half ar_attribute_form; /* Attribute Form. */
+ Dwarf_Half ar_attribute_form_direct;
+ /* Identical to ar_attribute_form except that if
+ the original form uleb was DW_FORM_indirect,
+ ar_attribute_form_direct contains DW_FORM_indirect
+ but ar_attribute_form contains the true form. */
+
+ Dwarf_CU_Context ar_cu_context;
+ Dwarf_Small *ar_debug_info_ptr;
+ Dwarf_Attribute ar_next;
+};
+
+/*
+ This structure provides the context for a compilation unit.
+ Thus, it contains the Dwarf_Debug, cc_dbg, that this cu
+ belongs to. It contains the information in the compilation
+ unit header, cc_length, cc_version_stamp, cc_abbrev_offset,
+ and cc_address_size, in the .debug_info section for that cu.
+ In addition, it contains the count, cc_count_cu, of the cu
+ number of that cu in the list of cu's in the .debug_info.
+ The count starts at 1, ie cc_count_cu is 1 for the first cu,
+ 2 for the second and so on. This struct also contains a
+ pointer, cc_abbrev_table, to a list of pairs of abbrev code
+ and a pointer to the start of that abbrev
+ in the .debug_abbrev section.
+
+ Each die will also contain a pointer to such a struct to
+ record the context for that die.
+
+ Notice that a pointer to the CU DIE itself is
+ Dwarf_Off off2 = cu_context->cc_debug_info_offset;
+ cu_die_info_ptr = dbg->de_debug_info.dss_data +
+ off2 + _dwarf_length_of_cu_header(dbg, off2);
+
+ **Updated by dwarf_next_cu_header in dwarf_die_deliv.c
+*/
+struct Dwarf_CU_Context_s {
+ Dwarf_Debug cc_dbg;
+ /* The sum of cc_length, cc_length_size, and cc_extension_size
+ is the total length of the CU including its header. */
+ Dwarf_Word cc_length;
+ /* cc_length_size is the size in bytes of an offset.
+ 4 for 32bit dwarf, 8 for 64bit dwarf (whether MIPS/IRIX
+ 64bit dwarf or standard 64bit dwarf using the extension
+ mechanism). */
+ Dwarf_Small cc_length_size;
+ /* cc_extension_size is zero unless this is standard
+ DWARF3 and later 64bit dwarf using the extension mechanism.
+ If it is the DWARF3 and later 64bit dwarf cc_extension
+ size is 4. So for 32bit dwarf and MIPS/IRIX 64bit dwarf
+ cc_extension_size is zero. */
+ Dwarf_Small cc_extension_size;
+ Dwarf_Half cc_version_stamp;
+ Dwarf_Sword cc_abbrev_offset;
+ Dwarf_Small cc_address_size;
+ /* cc_debug_info_offset is the offset in the section
+ of the CU header of this CU. Dwarf_Word
+ should be large enough. */
+ Dwarf_Word cc_debug_info_offset;
+ Dwarf_Byte_Ptr cc_last_abbrev_ptr;
+ Dwarf_Hash_Table cc_abbrev_hash_table;
+ Dwarf_CU_Context cc_next;
+ /*unsigned char cc_offset_length; */
+};
+
+/* Consolidates section-specific data in one place.
+ Section is an Elf specific term, intended as a general
+ term (for non-Elf objects some code must synthesize the
+ values somehow).
+ Makes adding more section-data much simpler. */
+struct Dwarf_Section_s {
+ Dwarf_Small * dss_data;
+ Dwarf_Unsigned dss_size;
+ Dwarf_Word dss_index;
+ /* dss_addr is the 'section address' which is only
+ non-zero for a GNU eh section.
+ Purpose: to handle DW_EH_PE_pcrel encoding. Leaving
+ it zero is fine for non-elf. */
+ Dwarf_Addr dss_addr;
+ Dwarf_Small dss_data_was_malloc;
+
+ /* For non-elf, leaving the following fields zero
+ will mean they are ignored. */
+ /* dss_link should be zero unless a section has a link
+ to another (sh_link). Used to access relocation data for
+ a section (and for symtab section, access its strtab). */
+ Dwarf_Word dss_link;
+ /* The following is used when reading .rela sections
+ (such sections appear in some .o files). */
+ Dwarf_Half dss_reloc_index; /* Zero means ignore the reloc fields. */
+ Dwarf_Small * dss_reloc_data;
+ Dwarf_Unsigned dss_reloc_size;
+ Dwarf_Addr dss_reloc_addr;
+ /* dss_reloc_symtab is the sh_link of a .rela to its .symtab, leave
+ it 0 if non-meaningful. */
+ Dwarf_Addr dss_reloc_symtab;
+ /* dss_reloc_link should be zero unless a reloc section has a link
+ to another (sh_link). Used to access the symtab for relocations
+ a section. */
+ Dwarf_Word dss_reloc_link;
+ /* Pointer to the elf symtab, used for elf .rela. Leave it 0
+ if not relevant. */
+ struct Dwarf_Section_s *dss_symtab;
+};
+
+/* Overview: if next_to_use== first, no error slots are used.
+ If next_to_use+1 (mod maxcount) == first the slots are all used
+*/
+struct Dwarf_Harmless_s {
+ unsigned dh_maxcount;
+ unsigned dh_next_to_use;
+ unsigned dh_first;
+ unsigned dh_errs_count;
+ char ** dh_errors;
+};
+
+struct Dwarf_Debug_s {
+ /* All file access methods and support data
+ are hidden in this structure.
+ We get a pointer, callers control the lifetime of the
+ structure and contents. */
+ struct Dwarf_Obj_Access_Interface_s *de_obj_file;
+
+ Dwarf_Handler de_errhand;
+ Dwarf_Ptr de_errarg;
+
+ /*
+ Context for the compilation_unit just read by a call to
+ dwarf_next_cu_header. **Updated by dwarf_next_cu_header in
+ dwarf_die_deliv.c */
+ Dwarf_CU_Context de_cu_context;
+
+ /*
+ Points to linked list of CU Contexts for the CU's already read.
+ These are only CU's read by dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_cu_context_list;
+
+ /*
+ Points to the last CU Context added to the list by
+ dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_cu_context_list_end;
+
+ /*
+ This is the list of CU contexts read for dwarf_offdie(). These
+ may read ahead of dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_offdie_cu_context;
+ Dwarf_CU_Context de_offdie_cu_context_end;
+
+ /* Offset of last byte of last CU read. */
+ Dwarf_Word de_info_last_offset;
+
+ /*
+ Number of bytes in the length, and offset field in various
+ .debug_* sections. It's not very meaningful, and is
+ only used in one 'approximate' calculation. */
+ Dwarf_Small de_length_size;
+
+ /* number of bytes in a pointer of the target in various .debug_
+ sections. 4 in 32bit, 8 in MIPS 64, ia64. */
+ Dwarf_Small de_pointer_size;
+
+ /* set at creation of a Dwarf_Debug to say if form_string should be
+ checked for valid length at every call. 0 means do the check.
+ non-zero means do not do the check. */
+ Dwarf_Small de_assume_string_in_bounds;
+
+ /*
+ Dwarf_Alloc_Hdr_s structs used to manage chunks that are
+ malloc'ed for each allocation type for structs. */
+ struct Dwarf_Alloc_Hdr_s de_alloc_hdr[ALLOC_AREA_REAL_TABLE_MAX];
+#ifdef DWARF_SIMPLE_MALLOC
+ struct simple_malloc_record_s * de_simple_malloc_base;
+#endif
+
+
+ /*
+ These fields are used to process debug_frame section. **Updated
+ by dwarf_get_fde_list in dwarf_frame.h */
+ /*
+ Points to contiguous block of pointers to Dwarf_Cie_s structs. */
+ Dwarf_Cie *de_cie_data;
+ /* Count of number of Dwarf_Cie_s structs. */
+ Dwarf_Signed de_cie_count;
+ /* Keep eh (GNU) separate!. */
+ Dwarf_Cie *de_cie_data_eh;
+ Dwarf_Signed de_cie_count_eh;
+ /*
+ Points to contiguous block of pointers to Dwarf_Fde_s structs. */
+ Dwarf_Fde *de_fde_data;
+ /* Count of number of Dwarf_Fde_s structs. */
+ Dwarf_Signed de_fde_count;
+ /* Keep eh (GNU) separate!. */
+ Dwarf_Fde *de_fde_data_eh;
+ Dwarf_Signed de_fde_count_eh;
+
+ struct Dwarf_Section_s de_debug_info;
+ struct Dwarf_Section_s de_debug_abbrev;
+ struct Dwarf_Section_s de_debug_line;
+ struct Dwarf_Section_s de_debug_loc;
+ struct Dwarf_Section_s de_debug_aranges;
+ struct Dwarf_Section_s de_debug_macinfo;
+ struct Dwarf_Section_s de_debug_pubnames;
+ struct Dwarf_Section_s de_debug_str;
+ struct Dwarf_Section_s de_debug_frame;
+
+ /* gnu: the g++ eh_frame section */
+ struct Dwarf_Section_s de_debug_frame_eh_gnu;
+
+ struct Dwarf_Section_s de_debug_pubtypes; /* DWARF3 .debug_pubtypes */
+
+ struct Dwarf_Section_s de_debug_funcnames;
+ struct Dwarf_Section_s de_debug_typenames; /* SGI IRIX extension essentially
+ identical to DWARF3 .debug_pubtypes. */
+ struct Dwarf_Section_s de_debug_varnames;
+ struct Dwarf_Section_s de_debug_weaknames;
+ struct Dwarf_Section_s de_debug_ranges;
+
+ /* For non-elf, simply leave the following two structs zeroed and
+ they will be ignored. */
+ struct Dwarf_Section_s de_elf_symtab;
+ struct Dwarf_Section_s de_elf_strtab;
+
+
+ void *(*de_copy_word) (void *, const void *, size_t);
+ unsigned char de_same_endian;
+ unsigned char de_elf_must_close; /* if non-zero, then
+ it was dwarf_init (not dwarf_elf_init)
+ so must elf_end() */
+
+ /* Default is DW_FRAME_INITIAL_VALUE from header. */
+ Dwarf_Half de_frame_rule_initial_value;
+
+ /* Default is DW_FRAME_LAST_REG_NUM. */
+ Dwarf_Half de_frame_reg_rules_entry_count;
+
+ Dwarf_Half de_frame_cfa_col_number;
+ Dwarf_Half de_frame_same_value_number;
+ Dwarf_Half de_frame_undefined_value_number;
+
+ unsigned char de_big_endian_object; /* non-zero if big-endian
+ object opened. */
+
+ struct Dwarf_Harmless_s de_harmless_errors;
+};
+
+typedef struct Dwarf_Chain_s *Dwarf_Chain;
+struct Dwarf_Chain_s {
+ void *ch_item;
+ Dwarf_Chain ch_next;
+};
+
+
+#define CURRENT_VERSION_STAMP 2 /* DWARF2 */
+#define CURRENT_VERSION_STAMP3 3 /* DWARF3 */
+#define CURRENT_VERSION_STAMP4 4 /* DWARF4 */
+
+ /* Size of cu header version stamp field. */
+#define CU_VERSION_STAMP_SIZE sizeof(Dwarf_Half)
+
+ /* Size of cu header address size field. */
+#define CU_ADDRESS_SIZE_SIZE sizeof(Dwarf_Small)
+
+void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len);
+
+#define ORIGINAL_DWARF_OFFSET_SIZE 4
+#define DISTINGUISHED_VALUE 0xffffffff
+#define DISTINGUISHED_VALUE_OFFSET_SIZE 8
+
+/*
+ We don't load the sections until they are needed. This function is
+ used to load the section.
+ */
+int _dwarf_load_section(Dwarf_Debug,
+ struct Dwarf_Section_s *,
+ Dwarf_Error *);
diff --git a/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c b/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c
new file mode 100644
index 0000000000..a6d943da0a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c
@@ -0,0 +1,209 @@
+/*
+
+ Copyright (C) 2000,2001,2002,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_elf_access.h"
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#ifdef HAVE_LIBELF_H
+#include <libelf.h>
+#else
+#ifdef HAVE_LIBELF_LIBELF_H
+#include <libelf/libelf.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DWARF_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_error(dbg, error, errval); return(retval);
+
+#define FALSE 0
+#define TRUE 1
+
+static int
+dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer,
+ int libdwarf_owns_elf,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg,
+ Dwarf_Error * error);
+
+
+/*
+ The basic dwarf initializer function for consumers using
+ libelf.
+ Return a libdwarf error code on error, return DW_DLV_OK
+ if this succeeds.
+*/
+int
+dwarf_init(int fd,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Debug * ret_dbg, Dwarf_Error * error)
+{
+ struct stat fstat_buf;
+ dwarf_elf_handle elf_file_pointer = 0;
+ /* ELF_C_READ is a portable value */
+ Elf_Cmd what_kind_of_elf_read = ELF_C_READ;
+
+#if !defined(S_ISREG)
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+ if (fstat(fd, &fstat_buf) != 0) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_ERROR, DW_DLV_ERROR);
+ }
+ if (!S_ISREG(fstat_buf.st_mode)) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_MODE_ERROR, DW_DLV_ERROR);
+ }
+
+ if (access != DW_DLC_READ) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
+ }
+
+ elf_version(EV_CURRENT);
+ /* changed to mmap request per bug 281217. 6/95 */
+#ifdef HAVE_ELF_C_READ_MMAP
+ /* ELF_C_READ_MMAP is an SGI IRIX specific enum value from IRIX
+ libelf.h meaning read but use mmap */
+ what_kind_of_elf_read = ELF_C_READ_MMAP;
+#endif /* !HAVE_ELF_C_READ_MMAP */
+
+ elf_file_pointer = elf_begin(fd, what_kind_of_elf_read, 0);
+ if (elf_file_pointer == NULL) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_ELF_BEGIN_ERROR, DW_DLV_ERROR);
+ }
+
+ return dwarf_elf_init_file_ownership(elf_file_pointer,
+ TRUE,
+ access,
+ errhand,
+ errarg,
+ ret_dbg,
+ error);
+}
+
+/*
+ An alternate dwarf setup call for consumers using
+ libelf.
+ When the caller has opened libelf already, so the
+ caller must free libelf.
+*/
+int
+dwarf_elf_init(dwarf_elf_handle elf_file_pointer,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg, Dwarf_Error * error)
+{
+ return dwarf_elf_init_file_ownership(elf_file_pointer,
+ FALSE,
+ access,
+ errhand,
+ errarg,
+ ret_dbg,
+ error);
+}
+
+
+/*
+ Initialize the ELF object access for libdwarf.
+ */
+static int
+dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer,
+ int libdwarf_owns_elf,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg,
+ Dwarf_Error * error)
+{
+ /* ELF is no longer tied to libdwarf. */
+ Dwarf_Obj_Access_Interface *binary_interface = 0;
+ int res = DW_DLV_OK;
+ int err = 0;
+
+ if (access != DW_DLC_READ) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
+ }
+
+ /* This allocates and fills in *binary_interface. */
+ res = dwarf_elf_object_access_init(
+ elf_file_pointer,
+ libdwarf_owns_elf,
+ &binary_interface,
+ &err);
+ if(res != DW_DLV_OK){
+ DWARF_DBG_ERROR(NULL, err, DW_DLV_ERROR);
+ }
+
+ /* This mallocs space and returns pointer thru ret_dbg,
+ saving the binary interface in 'ret-dbg' */
+ res = dwarf_object_init(binary_interface, errhand, errarg,
+ ret_dbg, error);
+ if(res != DW_DLV_OK){
+ dwarf_elf_object_access_finish(binary_interface);
+ }
+ return res;
+}
+
+
+/*
+ Frees all memory that was not previously freed
+ by dwarf_dealloc.
+ Aside from certain categories.
+
+ This is only applicable when dwarf_init() or dwarf_elf_init()
+ was used to init 'dbg'.
+*/
+int
+dwarf_finish(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ dwarf_elf_object_access_finish(dbg->de_obj_file);
+
+ return dwarf_object_finish(dbg, error);
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_print_lines.c b/usr/src/lib/libdwarf/common/dwarf_print_lines.c
new file mode 100644
index 0000000000..30c4889ee5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_print_lines.c
@@ -0,0 +1,737 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <time.h>
+#include "dwarf_line.h"
+
+/* FIXME Need to add prologue_end epilogue_begin isa fields. */
+static void
+print_line_header(void)
+{
+ printf
+ (" s b e\n"
+ " t l s\n"
+ " m c e\n"
+ " section op col t k q\n"
+ " offset code address file line umn ? ? ?\n");
+}
+
+/* FIXME: print new line values: prologue_end epilogue_begin isa */
+static void
+print_line_detail(char *prefix,
+ int opcode,
+ Dwarf_Unsigned address,
+ unsigned long file,
+ unsigned long line,
+ unsigned long column,
+ int is_stmt, int basic_block, int end_sequence,
+ int prologue_end, int epilogue_begin, int isa)
+{
+ printf("%-15s %2d 0x%08" DW_PR_DUx " "
+ "%2lu %4lu %2lu %1d %1d %1d\n",
+ prefix,
+ (int) opcode,
+ (Dwarf_Unsigned) address,
+ (unsigned long) file,
+ (unsigned long) line,
+ (unsigned long) column,
+ (int) is_stmt, (int) basic_block, (int) end_sequence);
+
+}
+
+
+/*
+ return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
+ If err_count_out is non-NULL, this is a special 'check'
+ call.
+*/
+int
+_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error,
+ int * err_count_out, int only_line_header)
+{
+ /*
+ This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr = 0;
+ Dwarf_Small *orig_line_ptr = 0;
+
+ /*
+ This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /*
+ Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr = 0;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr = 0;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = NULL;
+
+ /*
+ Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ struct Line_Table_Prefix_s prefix;
+
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word file = 1;
+ Dwarf_Word line = 1;
+ Dwarf_Word column = 0;
+ Dwarf_Bool is_stmt = false;
+ Dwarf_Bool basic_block = false;
+ Dwarf_Bool end_sequence = false;
+ Dwarf_Bool prologue_end = false;
+ Dwarf_Bool epilogue_begin = false;
+ Dwarf_Small isa = 0;
+
+
+ Dwarf_Sword i=0;
+
+ /*
+ This is the current opcode read from the statement program. */
+ Dwarf_Small opcode=0;
+
+
+ /*
+ These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num=0;
+ Dwarf_Word leb128_length=0;
+ Dwarf_Sword advance_line=0;
+ Dwarf_Half attrform = 0;
+ /*
+ This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc=0;
+
+ /* In case there are wierd bytes 'after' the line table
+ * prologue this lets us print something. This is a gcc
+ * compiler bug and we expect the bytes count to be 12.
+ */
+ Dwarf_Small* bogus_bytes_ptr = 0;
+ Dwarf_Unsigned bogus_bytes_count = 0;
+
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg=0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (error != NULL) {
+ *error = NULL;
+ }
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+
+ /* The list of relevant FORMs is small.
+ DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset
+ */
+ lres = dwarf_whatform(stmt_list_attr,&attrform,error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
+ attrform != DW_FORM_sec_offset ) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ orig_line_ptr = dbg->de_debug_line.dss_data;
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /*
+ If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+
+ dwarf_init_line_table_prefix(&prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,dbg->de_debug_line.dss_size - line_offset,
+ &line_ptr_out,
+ &prefix,
+ &bogus_bytes_ptr,
+ &bogus_bytes_count,
+ error,
+ err_count_out);
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+ line_ptr = line_ptr_out;
+ }
+ if(only_line_header) {
+ /* Just checking for header errors, nothing more here.*/
+ dwarf_free_line_table_prefix(&prefix);
+ return DW_DLV_OK;
+ }
+
+
+ printf("total line info length %ld bytes, "
+ "line offset 0x%" DW_PR_DUx " %" DW_PR_DSd "\n",
+ (long) prefix.pf_total_length,
+ (Dwarf_Unsigned) line_offset,
+ (Dwarf_Signed) line_offset);
+ printf("line table version %d\n",(int) prefix.pf_version);
+ printf("line table length field length %d prologue length %d\n",
+ (int)prefix.pf_length_field_length,
+ (int)prefix.pf_prologue_length);
+ printf("compilation_directory %s\n",
+ comp_dir ? ((char *) comp_dir) : "");
+
+ printf(" min instruction length %d\n",
+ (int) prefix.pf_minimum_instruction_length);
+ printf(" default is stmt %d\n", (int)
+ prefix.pf_default_is_stmt);
+ printf(" line base %d\n", (int)
+ prefix.pf_line_base);
+ printf(" line_range %d\n", (int)
+ prefix.pf_line_range);
+ printf(" opcode base %d\n", (int)
+ prefix.pf_opcode_base);
+ printf(" standard opcode count %d\n", (int)
+ prefix.pf_std_op_count);
+
+ for (i = 1; i < prefix.pf_opcode_base; i++) {
+ printf(" opcode[%2d] length %d\n", (int) i,
+ (int) prefix.pf_opcode_length_table[i - 1]);
+ }
+ printf(" include directories count %d\n", (int)
+ prefix.pf_include_directories_count);
+
+
+ for (i = 0; i < prefix.pf_include_directories_count; ++i) {
+ printf(" include dir[%d] %s\n",
+ (int) i, prefix.pf_include_directories[i]);
+ }
+ printf(" files count %d\n", (int)
+ prefix.pf_files_count);
+
+ for (i = 0; i < prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *lfile =
+ prefix.pf_line_table_file_entries + i;
+
+ Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time;
+ Dwarf_Unsigned di = lfile->lte_directory_index;
+ Dwarf_Unsigned fl = lfile->lte_length_of_file;
+
+ printf(" file[%d] %s (file-number: %d) \n",
+ (int) i, (char *) lfile->lte_filename,
+ (int)(i+1));
+
+ printf(" dir index %d\n", (int) di);
+ {
+ time_t tt = (time_t) tlm2;
+
+ printf(" last time 0x%x %s", /* ctime supplies
+ newline */
+ (unsigned) tlm2, ctime(&tt));
+ }
+ printf(" file length %ld 0x%lx\n",
+ (long) fl, (unsigned long) fl);
+
+
+ }
+
+
+ {
+ Dwarf_Unsigned offset = 0;
+ if(bogus_bytes_count > 0) {
+ Dwarf_Unsigned wcount = bogus_bytes_count;
+ Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr;
+ printf("*** DWARF CHECK: the line table prologue header_length "
+ " is %" DW_PR_DUu " too high, we pretend it is smaller."
+ "Section offset: %" DW_PR_DUu " (0x%" DW_PR_DUx ") ***\n",
+ wcount, boffset,boffset);
+ *err_count_out += 1;
+ }
+ offset = line_ptr - orig_line_ptr;
+
+ printf(" statement prog offset in section: %" DW_PR_DUu " 0x%" DW_PR_DUx "\n",
+ offset, offset);
+ }
+
+ /* Initialize the part of the state machine dependent on the
+ prefix. */
+ is_stmt = prefix.pf_default_is_stmt;
+
+
+ print_line_header();
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type = 0;
+
+ printf(" [0x%06" DW_PR_DSx "] ",
+ (Dwarf_Signed) (line_ptr - orig_line_ptr));
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ printf("*** DWARF CHECK: DISCARD standard opcode %d "
+ "with %d operands: "
+ "not understood.", opcode, opcnt);
+ *err_count_out += 1;
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ * Read and discard operands we don't
+ * understand.
+ * Arbitrary choice of unsigned read.
+ * Signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ printf(" %" DW_PR_DUu " (0x%" DW_PR_DUx ")",
+ (Dwarf_Unsigned) utmp2,
+ (Dwarf_Unsigned) utmp2);
+ }
+
+ printf("***\n");
+ /* do nothing, necessary ops done */
+ } else if (type == LOP_SPECIAL) {
+ /* This op code is a special op in the object, no matter
+ that it might fall into the standard op range in this
+ compile Thatis, these are special opcodes between
+ special_opcode_base and MAX_LINE_OP_CODE. (including
+ special_opcode_base and MAX_LINE_OP_CODE) */
+ char special[50];
+ unsigned origop = opcode;
+
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ sprintf(special, "Specialop %3u", origop);
+ print_line_detail(special,
+ opcode, address, (int) file, line, column,
+ is_stmt, basic_block, end_sequence,
+ prologue_end, epilogue_begin, isa);
+
+ basic_block = false;
+
+ } else if (type == LOP_STANDARD) {
+ switch (opcode) {
+
+ case DW_LNS_copy:{
+
+ print_line_detail("DW_LNS_copy",
+ opcode, address, file, line,
+ column, is_stmt, basic_block,
+ end_sequence, prologue_end,
+ epilogue_begin, isa);
+
+ basic_block = false;
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ printf("DW_LNS_advance_pc val %" DW_PR_DSd " 0x%" DW_PR_DUx "\n",
+ (Dwarf_Signed) (Dwarf_Word) utmp2,
+ (Dwarf_Unsigned) (Dwarf_Word) utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) advance_line,
+ (Dwarf_Signed) advance_line);
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ file = (Dwarf_Word) utmp2;
+ printf("DW_LNS_set_file %ld\n", (long) file);
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ column = (Dwarf_Word) utmp2;
+ printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) column, (Dwarf_Signed) column);
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+ is_stmt = !is_stmt;
+ printf("DW_LNS_negate_stmt\n");
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ printf("DW_LNS_set_basic_block\n");
+ basic_block = true;
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+
+ printf("DW_LNS_const_add_pc new address 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) address);
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd
+ " 0x%" DW_PR_DSx " new address 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) fixed_advance_pc,
+ (Dwarf_Signed) fixed_advance_pc,
+ (Dwarf_Signed) address);
+ break;
+ }
+ case DW_LNS_set_prologue_end:{
+
+ prologue_end = true;
+ printf("DW_LNS_set_prologue_end set true.\n");
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ epilogue_begin = true;
+ printf("DW_LNS_set_epilogue_begin set true.\n");
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ printf("DW_LNS_set_isa new value 0x%" DW_PR_DUx ".\n",
+ (Dwarf_Unsigned) utmp2);
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+ }
+
+
+ } else if (type == LOP_EXTENDED) {
+ Dwarf_Unsigned utmp3 = 0;
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ end_sequence = true;
+
+ print_line_detail("DW_LNE_end_sequence extended",
+ opcode, address, file, line,
+ column, is_stmt, basic_block,
+ end_sequence, prologue_end,
+ epilogue_begin, isa);
+
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = prefix.pf_default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+
+
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr,
+ die->di_cu_context->cc_address_size);
+
+ line_ptr += die->di_cu_context->cc_address_size;
+ printf("DW_LNE_set_address address 0x%" DW_PR_DUx "\n",
+ (Dwarf_Unsigned) address);
+ }
+
+ break;
+ }
+
+ case DW_LNE_define_file:{
+ Dwarf_Unsigned di = 0;
+ Dwarf_Unsigned tlm = 0;
+ Dwarf_Unsigned fl = 0;
+
+ Dwarf_Small *fn = (Dwarf_Small *) line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+
+ di = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ tlm = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ fl = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+
+ printf("DW_LNE_define_file %s \n", fn);
+ printf(" dir index %d\n", (int) di);
+ {
+ time_t tt3 = (time_t) tlm;
+
+ /* ctime supplies newline */
+ printf(" last time 0x%x %s",
+ (unsigned) tlm, ctime(&tt3));
+ }
+ printf(" file length %ld 0x%lx\n",
+ (long) fl, (unsigned long) fl);
+
+ break;
+ }
+
+ default:{
+ /* This is an extended op code we do not know about,
+ other than we know now many bytes it is
+ (and the op code and the bytes of operand). */
+
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_EXT_OPCODE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ printf("DW_LNE extended op 0x%x ",ext_opcode);
+ printf("Bytecount: " DW_PR_DUu , instr_length);
+ if(remaining_bytes > 0) {
+ printf(" linedata: 0x");
+ while (remaining_bytes > 0) {
+ printf("%02x",(unsigned char)(*(line_ptr)));
+ line_ptr++;
+ remaining_bytes--;
+ }
+ }
+ printf("\n");
+ }
+ break;
+ }
+
+ }
+ }
+
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
+
+/*
+ This is support for dwarfdump: making it possible
+ for clients wanting line detail info on stdout
+ to get that detail without including internal libdwarf
+ header information.
+ Caller passes in compilation unit DIE.
+ The _dwarf_ version is obsolete (though supported for
+ compatibility).
+ The dwarf_ version is preferred.
+ The functions are intentionally identical: having
+ _dwarf_print_lines call dwarf_print_lines might
+ better emphasize they are intentionally identical, but
+ that seemed slightly silly given how short the functions are.
+ Interface adds error_count (output value) February 2009.
+*/
+int
+dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error,int *error_count)
+{
+ int only_line_header = 0;
+ int res = _dwarf_internal_printlines(die, error,
+ error_count,
+ only_line_header);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ return res;
+}
+int
+_dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error)
+{
+ int only_line_header = 0;
+ int err_count = 0;
+ int res = _dwarf_internal_printlines(die, error,
+ &err_count,
+ only_line_header);
+ /* No way to get error count back in this interface */
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ return res;
+}
+
+/* The check is in case we are not printing full line data,
+ this gets some of the issues noted with .debug_line,
+ but not all. Call dwarf_print_lines() to get all issues.
+ Intended for apps like dwarfdump.
+*/
+void
+dwarf_check_lineheader(Dwarf_Die die, int *err_count_out)
+{
+ Dwarf_Error err;
+ int only_line_header = 1;
+ _dwarf_internal_printlines(die, &err,err_count_out,
+ only_line_header);
+ return;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_pubtypes.c b/usr/src/lib/libdwarf/common/dwarf_pubtypes.c
new file mode 100644
index 0000000000..330c1c6adc
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_pubtypes.c
@@ -0,0 +1,138 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+/* Reads DWARF3 .debug_pubtypes section. */
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_types.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_pubtypes(Dwarf_Debug dbg,
+ Dwarf_Type ** types,
+ Dwarf_Signed * ret_type_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_pubtypes,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_pubtypes.dss_data,
+ dbg->de_debug_pubtypes.dss_size,
+ (Dwarf_Global **) types, /* Type punning for sections
+ with identical format. */
+ ret_type_count, error,
+ DW_DLA_PUBTYPES_CONTEXT,
+ DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES,
+ so use DW_DLA_GLOBAL. */
+ DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD,
+ DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_pubtypes_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg,
+ (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_PUBTYPES_CONTEXT,
+ DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES,
+ so use DW_DLA_GLOBAL. */
+ DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_pubtypename(Dwarf_Type type_in, char **ret_name,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+ if (type == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_TYPE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *ret_name = (char *) (type->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_pubtype_type_die_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_die_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_pubtype_cu_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_cu_offset(type, ret_offset, error);
+
+}
+
+
+int
+dwarf_pubtype_name_offsets(Dwarf_Type type_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_name_offsets(type,
+ returned_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_query.c b/usr/src/lib/libdwarf/common/dwarf_query.c
new file mode 100644
index 0000000000..3f21abd039
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_query.c
@@ -0,0 +1,789 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+/* This is normally reliable.
+But not always.
+If different compilation
+units have different address sizes
+this may not give the correct value in all contexts.
+If the Elf offset size != address_size
+(for example if address_size = 4 but recorded in elf64 object)
+this may not give the correct value in all contexts.
+*/
+int
+dwarf_get_address_size(Dwarf_Debug dbg,
+ Dwarf_Half * ret_addr_size, Dwarf_Error * error)
+{
+ Dwarf_Half address_size = 0;
+
+ if (dbg == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ address_size = dbg->de_pointer_size;
+ *ret_addr_size = address_size;
+ return DW_DLV_OK;
+}
+
+/* This will be correct in all contexts where the
+ CU context of a DIE is known.
+*/
+int
+dwarf_get_die_address_size(Dwarf_Die die,
+ Dwarf_Half * ret_addr_size, Dwarf_Error * error)
+{
+ Dwarf_Half address_size = 0;
+ CHECK_DIE(die, DW_DLV_ERROR);
+ address_size = die->di_cu_context->cc_address_size;
+ *ret_addr_size = address_size;
+ return DW_DLV_OK;
+}
+
+int
+dwarf_dieoffset(Dwarf_Die die,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ *ret_offset = (die->di_debug_info_ptr -
+ die->di_cu_context->cc_dbg->de_debug_info.dss_data);
+ return DW_DLV_OK;
+}
+
+
+/*
+ This function returns the offset of
+ the die relative to the start of its
+ compilation-unit rather than .debug_info.
+ Returns DW_DLV_ERROR on error.
+*/
+int
+dwarf_die_CU_offset(Dwarf_Die die,
+ Dwarf_Off * cu_off, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cu_context = die->di_cu_context;
+
+ *cu_off =
+ (die->di_debug_info_ptr - cu_context->cc_dbg->de_debug_info.dss_data -
+ cu_context->cc_debug_info_offset);
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns the global offset
+ (meaning the section offset) and length of
+ the CU that this die is a part of.
+ Used for correctness checking by dwarfdump.
+*/
+int
+dwarf_die_CU_offset_range(Dwarf_Die die,
+ Dwarf_Off * cu_off,
+ Dwarf_Off * cu_length,
+ Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cu_context = die->di_cu_context;
+
+ *cu_off = cu_context->cc_debug_info_offset;
+ *cu_length = cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size;
+ return DW_DLV_OK;
+}
+
+
+
+int
+dwarf_tag(Dwarf_Die die, Dwarf_Half * tag, Dwarf_Error * error)
+{
+ CHECK_DIE(die, DW_DLV_ERROR);
+ *tag = (die->di_abbrev_list->ab_tag);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_attrlist(Dwarf_Die die,
+ Dwarf_Attribute ** attrbuf,
+ Dwarf_Signed * attrcnt, Dwarf_Error * error)
+{
+ Dwarf_Word attr_count = 0;
+ Dwarf_Word i = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Abbrev_List abbrev_list = 0;
+ Dwarf_Attribute new_attr = 0;
+ Dwarf_Attribute head_attr = NULL;
+ Dwarf_Attribute curr_attr = NULL;
+ Dwarf_Attribute *attr_ptr = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context,
+ die->di_abbrev_list->
+ ab_code);
+ if (abbrev_list == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_BAD);
+ return (DW_DLV_ERROR);
+ }
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+
+ info_ptr = die->di_debug_info_ptr;
+ SKIP_LEB128_WORD(info_ptr);
+
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+
+ if (attr != 0) {
+ new_attr =
+ (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1);
+ if (new_attr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form_direct = attr_form;
+ new_attr->ar_attribute_form = attr_form;
+ if (attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD does info_ptr update */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ attr_form = (Dwarf_Half) utmp6;
+ new_attr->ar_attribute_form = attr_form;
+ }
+ new_attr->ar_cu_context = die->di_cu_context;
+ new_attr->ar_debug_info_ptr = info_ptr;
+
+ {
+ Dwarf_Unsigned sov = _dwarf_get_size_of_val(dbg,
+ attr_form,
+ die->di_cu_context->cc_address_size,
+ info_ptr,
+ die->di_cu_context->cc_length_size);
+ info_ptr += sov;
+ }
+
+
+ if (head_attr == NULL)
+ head_attr = curr_attr = new_attr;
+ else {
+ curr_attr->ar_next = new_attr;
+ curr_attr = new_attr;
+ }
+ attr_count++;
+ }
+ } while (attr != 0 || attr_form != 0);
+
+ if (attr_count == 0) {
+ *attrbuf = NULL;
+ *attrcnt = 0;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ attr_ptr = (Dwarf_Attribute *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, attr_count);
+ if (attr_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_attr = head_attr;
+ for (i = 0; i < attr_count; i++) {
+ *(attr_ptr + i) = curr_attr;
+ curr_attr = curr_attr->ar_next;
+ }
+
+ *attrbuf = attr_ptr;
+ *attrcnt = attr_count;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function takes a die, and an attr, and returns
+ a pointer to the start of the value of that attr in
+ the given die in the .debug_info section. The form
+ is returned in *attr_form.
+
+ Returns NULL on error, or if attr is not found.
+ However, *attr_form is 0 on error, and positive
+ otherwise.
+*/
+static Dwarf_Byte_Ptr
+_dwarf_get_value_ptr(Dwarf_Die die,
+ Dwarf_Half attr, Dwarf_Half * attr_form)
+{
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Abbrev_List abbrev_list;
+ Dwarf_Half curr_attr = 0;
+ Dwarf_Half curr_attr_form = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+
+ abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context,
+ die->di_abbrev_list->ab_code);
+ if (abbrev_list == NULL) {
+ *attr_form = 0;
+ return (NULL);
+ }
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+
+ info_ptr = die->di_debug_info_ptr;
+ SKIP_LEB128_WORD(info_ptr);
+
+ do {
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp3);
+ curr_attr = (Dwarf_Half) utmp3;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp3);
+ curr_attr_form = (Dwarf_Half) utmp3;
+ if (curr_attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD updates info_ptr */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ curr_attr_form = (Dwarf_Half) utmp6;
+ }
+
+ if (curr_attr == attr) {
+ *attr_form = curr_attr_form;
+ return (info_ptr);
+ }
+
+ info_ptr += _dwarf_get_size_of_val(die->di_cu_context->cc_dbg,
+ curr_attr_form,
+ die->di_cu_context->cc_address_size,
+ info_ptr,
+ die->di_cu_context->cc_length_size);
+ } while (curr_attr != 0 || curr_attr_form != 0);
+
+ *attr_form = 1;
+ return (NULL);
+}
+
+
+int
+dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Unsigned string_offset = 0;
+ int res = DW_DLV_ERROR;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_name, &attr_form);
+ if (info_ptr == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(die->di_cu_context->cc_dbg, error,
+ DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+ }
+
+ if (attr_form == DW_FORM_string) {
+ *ret_name = (char *) (info_ptr);
+ return DW_DLV_OK;
+ }
+
+ dbg = die->di_cu_context->cc_dbg;
+ if (attr_form != DW_FORM_strp) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, string_offset, Dwarf_Unsigned,
+ info_ptr, die->di_cu_context->cc_length_size);
+
+ if (string_offset >= dbg->de_debug_str.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_STRING_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *ret_name = (char *) (dbg->de_debug_str.dss_data + string_offset);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_hasattr(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ if (_dwarf_get_value_ptr(die, attr, &attr_form) == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(die->di_cu_context->cc_dbg, error,
+ DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ *return_bool = false;
+ return DW_DLV_OK;
+ }
+
+ *return_bool = (true);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_attr(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Attribute * ret_attr, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+ Dwarf_Attribute attrib = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Debug dbg = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form);
+ if (info_ptr == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+ }
+
+ attrib = (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1);
+ if (attrib == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ attrib->ar_attribute = attr;
+ attrib->ar_attribute_form = attr_form;
+ attrib->ar_attribute_form_direct = attr_form;
+ attrib->ar_cu_context = die->di_cu_context;
+ attrib->ar_debug_info_ptr = info_ptr;
+ *ret_attr = (attrib);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_lowpc(Dwarf_Die die,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half address_size = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ dbg = die->di_cu_context->cc_dbg;
+ address_size = die->di_cu_context->cc_address_size;
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_low_pc, &attr_form);
+ if ((info_ptr == NULL && attr_form == 0) ||
+ (info_ptr != NULL && attr_form != DW_FORM_addr)) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (info_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ info_ptr, address_size);
+
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_highpc(Dwarf_Die die,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half address_size = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+ address_size = die->di_cu_context->cc_address_size;
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_high_pc, &attr_form);
+ if ((info_ptr == NULL && attr_form == 0) ||
+ (info_ptr != NULL && attr_form != DW_FORM_addr)) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (info_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ info_ptr, address_size);
+
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ Takes a die, an attribute attr, and checks if attr
+ occurs in die. Attr is required to be an attribute
+ whose form is in the "constant" class. If attr occurs
+ in die, the value is returned.
+ Returns DW_DLV_OK, DW_DLV_ERROR, or DW_DLV_NO_ENTRY as
+ appropriate. Sets the value thru the pointer return_val.
+ This function is meant to do all the
+ processing for dwarf_bytesize, dwarf_bitsize, dwarf_bitoffset,
+ and dwarf_srclang.
+*/
+static int
+_dwarf_die_attr_unsigned_constant(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Unsigned * return_val,
+ Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr info_ptr;
+ Dwarf_Half attr_form;
+ Dwarf_Unsigned ret_value;
+ Dwarf_Debug dbg;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ dbg = die->di_cu_context->cc_dbg;
+ info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form);
+ if (info_ptr != NULL) {
+ switch (attr_form) {
+
+ case DW_FORM_data1:
+ *return_val = (*(Dwarf_Small *) info_ptr);
+ return (DW_DLV_OK);
+
+ case DW_FORM_data2:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Shalf));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_data4:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_sfixed));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_data8:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Unsigned));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_udata:
+ *return_val = (_dwarf_decode_u_leb128(info_ptr, NULL));
+ return (DW_DLV_OK);
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ if (attr_form == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+int
+dwarf_bytesize(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_byte_size,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+int
+dwarf_bitsize(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_bit_size,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+int
+dwarf_bitoffset(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die,
+ DW_AT_bit_offset, &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+/* Refer section 3.1, page 21 in Dwarf Definition. */
+int
+dwarf_srclang(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_language,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+/* Refer section 5.4, page 37 in Dwarf Definition. */
+int
+dwarf_arrayorder(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_ordering,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+/*
+ Return DW_DLV_OK if ok
+ DW_DLV_ERROR if failure.
+
+ If the die and the attr are not related the result is
+ meaningless.
+*/
+int
+dwarf_attr_offset(Dwarf_Die die, Dwarf_Attribute attr,
+ Dwarf_Off * offset /* return offset thru this ptr */,
+ Dwarf_Error * error)
+{
+ Dwarf_Off attroff = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ attroff = (attr->ar_debug_info_ptr -
+ die->di_cu_context->cc_dbg->de_debug_info.dss_data);
+ *offset = attroff;
+ return DW_DLV_OK;
+}
+
+int
+dwarf_die_abbrev_code(Dwarf_Die die)
+{
+ return die->di_abbrev_code;
+}
+
+/* Helper function for finding form class. */
+static enum Dwarf_Form_Class
+dw_get_special_offset(Dwarf_Half attrnum)
+{
+ switch(attrnum) {
+ case DW_AT_stmt_list:
+ return DW_FORM_CLASS_LINEPTR;
+ case DW_AT_macro_info:
+ return DW_FORM_CLASS_MACPTR;
+ case DW_AT_ranges:
+ return DW_FORM_CLASS_RANGELISTPTR;
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ return DW_FORM_CLASS_LOCLISTPTR;
+ case DW_AT_sibling:
+ case DW_AT_byte_size :
+ case DW_AT_bit_offset :
+ case DW_AT_bit_size :
+ case DW_AT_discr :
+ case DW_AT_import :
+ case DW_AT_common_reference:
+ case DW_AT_containing_type:
+ case DW_AT_default_value:
+ case DW_AT_lower_bound:
+ case DW_AT_bit_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_abstract_origin:
+ case DW_AT_base_types:
+ case DW_AT_count:
+ case DW_AT_friend:
+ case DW_AT_namelist_item:
+ case DW_AT_priority:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_byte_stride:
+ case DW_AT_extension:
+ case DW_AT_trampoline:
+ case DW_AT_small:
+ case DW_AT_object_pointer:
+ case DW_AT_signature:
+ return DW_FORM_CLASS_REFERENCE;
+ case DW_AT_MIPS_fde: /* SGI/IRIX extension */
+ return DW_FORM_CLASS_FRAMEPTR;
+ }
+ return DW_FORM_CLASS_UNKNOWN;
+}
+
+/* It takes 4 pieces of data (including the FORM)
+ to accurately determine the form 'class' as documented
+ in the DWARF spec. This is per DWARF4, but will work
+ for DWARF2 or 3 as well. */
+enum Dwarf_Form_Class dwarf_get_form_class(
+ Dwarf_Half dwversion,
+ Dwarf_Half attrnum,
+ Dwarf_Half offset_size,
+ Dwarf_Half form)
+{
+ switch(form) {
+ case DW_FORM_addr: return DW_FORM_CLASS_ADDRESS;
+
+ case DW_FORM_data2: return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_data4:
+ if(dwversion <= 3 && offset_size == 4) {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_data8:
+ if(dwversion <= 3 && offset_size == 8) {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_sec_offset:
+ {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ /* We do not know what this is. */
+ break;
+
+ case DW_FORM_string: return DW_FORM_CLASS_STRING;
+ case DW_FORM_strp: return DW_FORM_CLASS_STRING;
+
+ case DW_FORM_block: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block1: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block2: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block4: return DW_FORM_CLASS_BLOCK;
+
+ case DW_FORM_data1: return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_sdata: return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_udata: return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_ref_addr: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref1: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref2: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref4: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref8: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref_udata: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref_sig8: return DW_FORM_CLASS_REFERENCE;
+
+ case DW_FORM_exprloc: return DW_FORM_CLASS_EXPRLOC;
+
+ case DW_FORM_flag: return DW_FORM_CLASS_FLAG;
+ case DW_FORM_flag_present: return DW_FORM_CLASS_FLAG;
+
+
+ case DW_FORM_indirect:
+ default:
+ break;
+ };
+ return DW_FORM_CLASS_UNKNOWN;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_ranges.c b/usr/src/lib/libdwarf/common/dwarf_ranges.c
new file mode 100644
index 0000000000..ae6d5cf9b5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_ranges.c
@@ -0,0 +1,171 @@
+/*
+
+ Copyright (C) 2008-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+#include "config.h"
+#include <stdlib.h>
+#include "dwarf_incl.h"
+
+struct ranges_entry {
+ struct ranges_entry *next;
+ Dwarf_Ranges cur;
+};
+
+
+#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
+int dwarf_get_ranges_a(Dwarf_Debug dbg,
+ Dwarf_Off rangesoffset,
+ Dwarf_Die die,
+ Dwarf_Ranges ** rangesbuf,
+ Dwarf_Signed * listlen,
+ Dwarf_Unsigned * bytecount,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *rangeptr = 0;
+ Dwarf_Small *beginrangeptr = 0;
+ Dwarf_Small *section_end = 0;
+ unsigned entry_count = 0;
+ struct ranges_entry *base = 0;
+ struct ranges_entry *last = 0;
+ struct ranges_entry *curre = 0;
+ Dwarf_Ranges * ranges_data_out = 0;
+ unsigned copyindex = 0;
+ Dwarf_Half address_size = 0;
+ int res = DW_DLV_ERROR;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ if(rangesoffset >= dbg->de_debug_ranges.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+
+ }
+ address_size = _dwarf_get_address_size(dbg, die);
+ section_end = dbg->de_debug_ranges.dss_data +
+ dbg->de_debug_ranges.dss_size;
+ rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset;
+ beginrangeptr = rangeptr;
+
+ for(;;) {
+ struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1);
+ if(!re) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return (DW_DLV_ERROR);
+ }
+ if(rangeptr >= section_end) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ if((rangeptr + (2*address_size)) > section_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ entry_count++;
+ READ_UNALIGNED(dbg,re->cur.dwr_addr1,
+ Dwarf_Addr, rangeptr,
+ address_size);
+ rangeptr += address_size;
+ READ_UNALIGNED(dbg,re->cur.dwr_addr2 ,
+ Dwarf_Addr, rangeptr,
+ address_size);
+ rangeptr += address_size;
+ if(!base) {
+ base = re;
+ last = re;
+ } else {
+ last->next = re;
+ last = re;
+ }
+ if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
+ re->cur.dwr_type = DW_RANGES_END;
+ break;
+ } else if ( re->cur.dwr_addr1 == MAX_ADDR) {
+ re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION;
+ } else {
+ re->cur.dwr_type = DW_RANGES_ENTRY;
+ }
+ }
+
+ ranges_data_out = (Dwarf_Ranges *)
+ _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
+ if(!ranges_data_out) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return (DW_DLV_ERROR);
+ }
+ curre = base;
+ *rangesbuf = ranges_data_out;
+ *listlen = entry_count;
+ for( copyindex = 0; curre && (copyindex < entry_count);
+ ++copyindex,++ranges_data_out) {
+
+ struct ranges_entry *r = curre;
+ *ranges_data_out = curre->cur;
+ curre = curre->next;
+ free(r);
+ }
+ /* Callers will often not care about the bytes used. */
+ if(bytecount) {
+ *bytecount = rangeptr - beginrangeptr;
+ }
+ return DW_DLV_OK;
+}
+int dwarf_get_ranges(Dwarf_Debug dbg,
+ Dwarf_Off rangesoffset,
+ Dwarf_Ranges ** rangesbuf,
+ Dwarf_Signed * listlen,
+ Dwarf_Unsigned * bytecount,
+ Dwarf_Error * error)
+{
+ Dwarf_Die die = 0;
+ int res = dwarf_get_ranges_a(dbg,rangesoffset,die,
+ rangesbuf,listlen,bytecount,error);
+ return res;
+}
+
+void
+dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf,
+ Dwarf_Signed rangecount)
+{
+ dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES);
+
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_sort_line.c b/usr/src/lib/libdwarf/common/dwarf_sort_line.c
new file mode 100644
index 0000000000..3576614129
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_sort_line.c
@@ -0,0 +1,733 @@
+/*
+ Copyright (C) 2000,2002,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+/* This file was designed for SGI IRIX compiler use.
+ The static linker can rearrange the order of functions
+ in the layout in memory
+ and provided each has the right form
+ this will (when called by the SGI IRIX
+ static linker) rearrange the table so the line table
+ is arranged in the same order as the memory layout. */
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_line.h"
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#define MINIMUM_POSSIBLE_PROLOG_LEN 10 /* 10 is based on */
+ /* the definition of the DWARF2/3 line table prolog. The value
+ here should be >8 (accounting for a 64 bit read) and <= the
+ length of a legal DWARF2/3 line prolog, which is at least 10
+ bytes long (but can be longer). What this constant helps
+ avoid is reading past the end of a malloc'd buffer in
+ _dwarf_update_line_sec(). */
+
+static int
+ _dwarf_update_line_sec(Dwarf_Small * line_ptr,
+ unsigned long remaining_bytes,
+ int *any_change,
+ int length_size,
+ int *err_code, Dwarf_Small ** new_line_ptr);
+
+/* Used to construct
+ a linked list of so we can sort and reorder the line info.
+*/
+struct a_line_area {
+ Dwarf_Addr ala_address; /* from DW_LNE_set_address */
+ Dwarf_Unsigned ala_offset; /* byte offset in buffer */
+ Dwarf_Unsigned ala_length; /* byte length in buffer */
+ long ala_entry_num; /* to guarantee stable sort */
+ struct a_line_area *ala_next;
+};
+
+
+/*
+ Written to support the SGI IRIX static linker.
+ It helps SGI IRIX ld
+ rearrange lines in .debug_line in a .o created with a text
+ section per function. The SGI IRIX linker option is:
+ -OPT:procedure_reorder=ON
+ where ld-cord (cord(1)ing by ld,
+ not by cord(1)) may have changed the function order.
+
+ Returns
+ DW_DLV_OK if nothing went wrong.
+ DW_DLV_ERROR if could not do anything due to
+ error. the original buffer is unchanged.
+
+ is_64_bit must be passed in by caller and tells
+ if this is a 32 or 64bit pointer object section
+ being processed.
+
+ err_code must be a non-null pointer to integer.
+ If DW_DLV_ERROR is returned that integer is set
+ to a dwarf error code so the caller may
+ print it for diagnostic purposes.
+
+ *any_change is set here
+ set 0 if no sorting (movement) done.
+ set 1 if some sorting (movement) done.
+ on all returns. On error return sets to 0.
+
+ The _dwarf name form is now obsolete,
+ the dwarf_ name for is preferred.
+ Both names supported.
+
+*/
+int
+_dwarf_ld_sort_lines(void *orig_buffer,
+ unsigned long buffer_len,
+ int is_64_bit, int *any_change, int *err_code)
+{
+ return dwarf_ld_sort_lines(orig_buffer,buffer_len,
+ is_64_bit,any_change,err_code);
+}
+int
+dwarf_ld_sort_lines(void *orig_buffer,
+ unsigned long buffer_len,
+ int is_64_bit, int *any_change, int *err_code)
+{
+
+ int length_size = 4;
+ Dwarf_Small *orig_line_ptr; /* our local copy of the user's input
+ buffer */
+ Dwarf_Small *line_ptr; /* starts at orig_line_ptr, gets
+ incremented thru to end of our copy
+ of the input buffer */
+ Dwarf_Small *new_line_ptr; /* output of _dwarf_update_line_sec(),
+ used to update line_ptr as we pass
+ thru compilation units in a .o
+ .debug_line */
+
+ unsigned long remaining_bytes = buffer_len; /* total length of
+ original area left
+ to be processed.
+ Changes as we pass
+ thru compilation
+ units in a .o
+ .debug_line */
+
+ int sec_res;
+ int lany_change = 0;
+ int did_change = 0;
+
+ if (is_64_bit)
+ length_size = 8;
+
+ *any_change = 0;
+ line_ptr = malloc(buffer_len);
+ if (!line_ptr) {
+ *err_code = DW_DLE_ALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ orig_line_ptr = line_ptr;
+ memcpy(line_ptr, orig_buffer, buffer_len);
+
+
+ /*
+ We must iterate thru each of a set of prologues and line data.
+ We process each set in turn. If all pass, we update the
+ passed-in buffer. */
+ sec_res = DW_DLV_OK;
+
+ for (sec_res = _dwarf_update_line_sec(line_ptr,
+ remaining_bytes,
+ &lany_change,
+ length_size,
+ err_code,
+ &new_line_ptr);
+ (sec_res == DW_DLV_OK) && (remaining_bytes > 0);
+ sec_res = _dwarf_update_line_sec(line_ptr,
+ remaining_bytes,
+ &lany_change,
+ length_size,
+ err_code, &new_line_ptr)) {
+ long bytes_used = new_line_ptr - line_ptr;
+
+ line_ptr = new_line_ptr;
+ remaining_bytes -= bytes_used;
+ if (lany_change) {
+ did_change = 1;
+ }
+ if (remaining_bytes > 0) {
+ continue;
+ }
+ break;
+ }
+ if (sec_res == DW_DLV_ERROR) {
+ free(orig_line_ptr);
+ return sec_res;
+ }
+
+
+ /* all passed */
+ if (did_change) {
+ /* So update the passed in buffer orig_buffer is caller's input
+ area. orig_line_ptr is our modified copy of input area. */
+ memcpy(orig_buffer, orig_line_ptr, buffer_len);
+ *any_change = 1;
+ }
+ free(orig_line_ptr);
+
+ return sec_res;
+}
+
+
+/* By setting ala_entry_num we guarantee a stable sort,
+ no duplicates
+ Sorting in address order.
+*/
+static int
+cmpr(const void *lin, const void *rin)
+{
+ const struct a_line_area *l = lin;
+ const struct a_line_area *r = rin;
+
+ if (l->ala_address < r->ala_address) {
+ return -1;
+ }
+ if (l->ala_address > r->ala_address) {
+ return 1;
+ }
+ if (l->ala_entry_num < r->ala_entry_num) {
+ return -1;
+ }
+ if (l->ala_entry_num > r->ala_entry_num) {
+ return 1;
+ }
+ return 0; /* should never happen. */
+}
+
+/* The list of line area records is no longer needed.
+ Free the data allocated. */
+static void
+free_area_data(struct a_line_area *arp)
+{
+ while(arp) {
+ struct a_line_area *next = arp->ala_next;
+ free(arp);
+ arp = next;
+ }
+}
+
+/*
+ On entry:
+ line_ptr must point to first
+ byte of a line group for one (original) .o
+
+ remaining_bytes is the size of the area pointed to
+ by line_ptr: may be larger than the
+ current original compilation unit .
+
+ length size is 4 for 32bit pointers, 8 for 64bit pointers
+ in the data pointed to.
+
+
+ On return:
+ return DW_DLV_OK if all ok. (ignore
+ *err_code in this case)
+
+ return DW_DLV_ERROR and set *err_code if an error.
+
+ If some line data was moved around, set *any_change to 1.
+ If error or no movement, set *any_change to 0;
+
+ Set *new_line_ptr to one-byte-past the end of the
+ current original compilation unit (not necessary
+ if returning DW_DLV_ERROR, but not harmful).
+
+
+ This copies the entire array to a malloc area, then
+ mallocs pieces of it (another malloc) for sorting a CU entries
+ and copying back. Then at end the whole new thing copied in.
+ The result is that on error, the input is not touched.
+
+ An alternative would be to just update a piece at a time
+ and on error stop updating but leave what was done, done.
+ This alternative would save some temporary malloc space.
+
+
+*/
+static int
+_dwarf_update_line_sec(Dwarf_Small * line_ptr,
+ unsigned long remaining_bytes,
+ int *any_change,
+ int length_size,
+ int *err_code, Dwarf_Small ** new_line_ptr)
+{
+
+
+ /*
+ This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /*
+ This points to the end of the statement program prologue for the
+ current cu, and serves to check that the prologue was correctly
+ decoded. */
+
+ Dwarf_Small *orig_line_ptr = 0;
+
+ /* These are the fields of the statement program header. */
+ struct Dwarf_Debug_s dbg_data;
+ Dwarf_Debug dbg = &dbg_data;
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word line = 1;
+ Dwarf_Bool is_stmt = false;
+
+ /* Dwarf_Bool prologue_end; Dwarf_Bool epilogue_begin; */
+ Dwarf_Small isa = 0;
+
+
+ struct a_line_area *area_base = 0;
+ struct a_line_area *area_current = 0;
+ long area_count = 0;
+
+ Dwarf_Addr last_address = 0;
+ int need_to_sort = 0;
+
+ /*
+ This is the current opcode read from the statement program. */
+ Dwarf_Small opcode = 0;
+
+
+ /*
+ These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num = 0;
+ Dwarf_Sword advance_line = 0;
+
+ /*
+ This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc = 0;
+
+ /* This is the length of an extended opcode instr. */
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+ struct Line_Table_Prefix_s prefix;
+
+
+
+ memset(dbg, 0, sizeof(struct Dwarf_Debug_s));
+ dbg->de_copy_word = memcpy;
+ /*
+ Following is a straightforward decoding of the statement program
+ prologue information. */
+ *any_change = 0;
+
+
+ orig_line_ptr = line_ptr;
+ if (remaining_bytes < MINIMUM_POSSIBLE_PROLOG_LEN) {
+ /* We are at the end. Remaining should be zero bytes, padding.
+ This is really just 'end of CU buffer' not an error. The is
+ no 'entry' left so report there is none. We don't want to
+ READ_UNALIGNED the total_length below and then belatedly
+ discover that we read off the end already. */
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ dwarf_init_line_table_prefix(&prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ Dwarf_Error error;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ remaining_bytes,
+ &line_ptr_out,
+ &prefix,
+ NULL, NULL,&error,
+ NULL);
+
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = dwarf_errno(error);
+ dwarf_dealloc(dbg, error, DW_DLA_ERROR);
+ free_area_data(area_base);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+
+ line_ptr = line_ptr_out;
+ }
+
+
+ /* Initialize the state machine. */
+ /* file = 1; */
+ /* column = 0; */
+ is_stmt = prefix.pf_default_is_stmt;
+ /* basic_block = false; */
+ /* end_sequence = false; */
+ /* prologue_end = false; */
+ /* epilogue_begin = false; */
+ isa = 0;
+
+
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type;
+
+ Dwarf_Small *stmt_prog_entry_start = line_ptr;
+
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ ** Read and discard operands we don't
+ ** understand.
+ ** arbitrary choice of unsigned read.
+ ** signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ }
+
+ } else if (type == LOP_SPECIAL) {
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ /* basic_block = false; */
+
+
+ } else if (type == LOP_STANDARD) {
+
+
+ switch (opcode) {
+
+
+ case DW_LNS_copy:{
+
+ /* basic_block = false; */
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ /* file = (Dwarf_Word)utmp2; */
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ /* column = (Dwarf_Word)utmp2; */
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+
+ is_stmt = !is_stmt;
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ /* basic_block = true; */
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ break;
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_prologue_end:{
+
+ /* prologue_end = true; */
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ /* epilogue_begin = true; */
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = DW_DLE_LINE_NUM_OPERANDS_BAD;
+ free_area_data(area_base);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+
+ }
+ } else if (type == LOP_EXTENDED) {
+
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ /* end_sequence = true; */
+
+ address = 0;
+ /* file = 1; */
+ line = 1;
+ /* column = 0; */
+ is_stmt = prefix.pf_default_is_stmt;
+ /* basic_block = false; */
+ /* end_sequence = false; */
+ /* prologue_end = false; */
+ /* epilogue_begin = false; */
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ struct a_line_area *area;
+
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr, length_size);
+ /* Here we need to remember the offset into the
+ buffer and check to see if address went
+ down. */
+ if (address < last_address) {
+ need_to_sort = 1;
+ }
+ last_address = address;
+
+ area = malloc(sizeof(struct a_line_area));
+ area->ala_address = address;
+ area->ala_offset = stmt_prog_entry_start -
+ orig_line_ptr;
+ area->ala_entry_num = area_count;
+ area->ala_next = 0;
+ area->ala_length = 0;
+ if (area_current) {
+ area_current->ala_next = area;
+ area_current->ala_length =
+ area->ala_offset -
+ area_current->ala_offset;
+ }
+ ++area_count;
+ area_current = area;
+ if (area_base == 0) {
+ area_base = area;
+ }
+
+ line_ptr += length_size;
+ }
+ break;
+ }
+
+ case DW_LNE_define_file:{
+ break;
+ }
+
+ default:{
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ line_ptr += remaining_bytes;
+ break;
+ }
+ }
+
+ }
+ }
+
+
+ *new_line_ptr = line_ptr;
+ if (!need_to_sort) {
+ dwarf_free_line_table_prefix(&prefix);
+ free_area_data(area_base);
+ return (DW_DLV_OK);
+ }
+
+ /* So now we have something to sort. First, finish off the last
+ area record: */
+ area_current->ala_length = (line_ptr - orig_line_ptr)
+ -area_current->ala_offset;
+
+ /* Build and sort a simple array of sections. Forcing a stable sort
+ by comparing on sequence number. We will use the sorted list to
+ move sections of this part of the line table. Each 'section'
+ starting with a DW_LNE_set_address opcode, on the assumption
+ that such only get out of order where there was an ld-cord
+ function rearrangement and that it is meaningful to restart the
+ line info there. */
+ {
+ struct a_line_area *ala_array;
+ struct a_line_area *local;
+ long start_len;
+ Dwarf_Small *new_area;
+ long i;
+
+ ala_array = malloc(area_count * sizeof(struct a_line_area));
+ if (!ala_array) {
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = DW_DLE_ALLOC_FAIL;
+ free_area_data(area_base);
+ return DW_DLV_ERROR;
+ }
+
+ for (local = area_base, i = 0; local;
+ local = local->ala_next, ++i) {
+
+ ala_array[i] = *local;
+ }
+ free_area_data(area_base);
+ /* Zero the stale pointers so we don't use them accidentally. */
+ area_base = 0;
+ area_current = 0;
+
+ qsort(ala_array, area_count, sizeof(struct a_line_area), cmpr);
+
+ /* Now we must rearrange the pieces of the line table. */
+
+ start_len =
+ (prefix.pf_line_prologue_start +
+ prefix.pf_prologue_length) - orig_line_ptr;
+ new_area = malloc(remaining_bytes);
+ if (!new_area) {
+ free(ala_array);
+ *err_code = DW_DLE_ALLOC_FAIL;
+ dwarf_free_line_table_prefix(&prefix);
+ return DW_DLV_ERROR;
+ }
+ memcpy(new_area, orig_line_ptr, start_len);
+ line_ptr = new_area + start_len;
+ for (i = 0; i < area_count; ++i) {
+ memcpy(line_ptr, orig_line_ptr +
+ ala_array[i].ala_offset, ala_array[i].ala_length);
+ line_ptr += ala_array[i].ala_length;
+ }
+
+ memcpy(orig_line_ptr, new_area, remaining_bytes);
+
+ free(new_area);
+ free(ala_array);
+ ala_array = 0;
+ new_area = 0;
+ }
+
+ *any_change = 1;
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_string.c b/usr/src/lib/libdwarf/common/dwarf_string.c
new file mode 100644
index 0000000000..fafa5a097c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_string.c
@@ -0,0 +1,79 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+
+int
+dwarf_get_str(Dwarf_Debug dbg,
+ Dwarf_Off offset,
+ char **string,
+ Dwarf_Signed * returned_str_len, Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (offset == dbg->de_debug_str.dss_size) {
+ /* Normal (if we've iterated thru the set of strings using
+ dwarf_get_str and are at the end). */
+ return DW_DLV_NO_ENTRY;
+ }
+ if (offset > dbg->de_debug_str.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ if (string == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_STRING_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *string = (char *) dbg->de_debug_str.dss_data + offset;
+
+ *returned_str_len = (strlen(*string));
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_stubs.c b/usr/src/lib/libdwarf/common/dwarf_stubs.c
new file mode 100644
index 0000000000..f2c1f7fd45
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_stubs.c
@@ -0,0 +1,50 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+
+
+
+ /*ARGSUSED*/ int
+dwarf_nextglob(Dwarf_Debug dbg,
+ Dwarf_Global glob,
+ Dwarf_Global * returned_nextglob, Dwarf_Error * error)
+{
+ return (DW_DLV_NO_ENTRY);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_types.c b/usr/src/lib/libdwarf/common/dwarf_types.c
new file mode 100644
index 0000000000..d547805289
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_types.c
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_types.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_types(Dwarf_Debug dbg,
+ Dwarf_Type ** types,
+ Dwarf_Signed * ret_type_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_typenames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_typenames.dss_data,
+ dbg->de_debug_typenames.dss_size,
+ (Dwarf_Global **) types, /* type punning, Dwarf_Type is
+ never a completed type */
+ ret_type_count,
+ error,
+ DW_DLA_TYPENAME_CONTEXT,
+ DW_DLA_TYPENAME,
+ DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_types_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_TYPENAME_CONTEXT,
+ DW_DLA_TYPENAME, DW_DLA_LIST);
+ return;
+}
+
+
+int
+dwarf_typename(Dwarf_Type type_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ if (type == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_TYPE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (type->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_type_die_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_die_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_type_cu_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_cu_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_type_name_offsets(Dwarf_Type type_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+ return dwarf_global_name_offsets(type,
+ returned_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_types.h b/usr/src/lib/libdwarf/common/dwarf_types.h
new file mode 100644
index 0000000000..ebd31c6c79
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_types.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+typedef struct Dwarf_Type_Context_s *Dwarf_Type_Context;
+
+/* type never completed see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_util.c b/usr/src/lib/libdwarf/common/dwarf_util.c
new file mode 100644
index 0000000000..01e0dd755d
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_util.c
@@ -0,0 +1,547 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+
+
+/*
+ Given a form, and a pointer to the bytes encoding
+ a value of that form, val_ptr, this function returns
+ the length, in bytes, of a value of that form.
+ When using this function, check for a return of 0
+ a recursive DW_FORM_INDIRECT value.
+*/
+Dwarf_Unsigned
+_dwarf_get_size_of_val(Dwarf_Debug dbg,
+ Dwarf_Unsigned form,
+ Dwarf_Half address_size,
+ Dwarf_Small * val_ptr, int v_length_size)
+{
+ Dwarf_Unsigned length = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned form_indirect = 0;
+ Dwarf_Unsigned ret_value = 0;
+
+ switch (form) {
+
+ default: /* Handles form = 0. */
+ return (form);
+
+ case DW_FORM_addr:
+ if(address_size) {
+ return address_size;
+ }
+ /* This should never happen, address_size should be set. */
+ return (dbg->de_pointer_size);
+
+ /* DWARF2 was wrong on the size of the attribute for
+ DW_FORM_ref_addr. We assume compilers are using the
+ corrected DWARF3 text (for 32bit pointer target objects pointer and
+ offsets are the same size anyway). */
+ case DW_FORM_ref_addr:
+ return (v_length_size);
+
+ case DW_FORM_block1:
+ return (*(Dwarf_Small *) val_ptr + 1);
+
+ case DW_FORM_block2:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_Half));
+ return (ret_value + sizeof(Dwarf_Half));
+
+ case DW_FORM_block4:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_ufixed));
+ return (ret_value + sizeof(Dwarf_ufixed));
+
+
+ case DW_FORM_data1:
+ return (1);
+
+ case DW_FORM_data2:
+ return (2);
+
+ case DW_FORM_data4:
+ return (4);
+
+ case DW_FORM_data8:
+ return (8);
+
+ case DW_FORM_string:
+ return (strlen((char *) val_ptr) + 1);
+
+ case DW_FORM_block:
+ case DW_FORM_exprloc:
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (length + leb128_length);
+
+ case DW_FORM_flag_present:
+ return (0);
+ case DW_FORM_flag:
+ return (1);
+
+ case DW_FORM_sec_offset:
+ /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */
+ return (v_length_size);
+
+ case DW_FORM_ref_udata:
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+
+ case DW_FORM_indirect:
+ {
+ Dwarf_Word indir_len = 0;
+
+ form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
+ if (form_indirect == DW_FORM_indirect) {
+ return (0); /* We are in big trouble: The true form
+ of DW_FORM_indirect is
+ DW_FORM_indirect? Nonsense. Should
+ never happen. */
+ }
+ return (indir_len + _dwarf_get_size_of_val(dbg,
+ form_indirect,
+ address_size,
+ val_ptr + indir_len,
+ v_length_size));
+ }
+
+ case DW_FORM_ref1:
+ return (1);
+
+ case DW_FORM_ref2:
+ return (2);
+
+ case DW_FORM_ref4:
+ return (4);
+
+ case DW_FORM_ref8:
+ return (8);
+
+ case DW_FORM_sdata:
+ _dwarf_decode_s_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+
+ case DW_FORM_strp:
+ return (v_length_size);
+
+ case DW_FORM_udata:
+ _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+ }
+}
+
+/* We allow an arbitrary number of HT_MULTIPLE entries
+ before resizing. It seems up to 20 or 30
+ would work nearly as well.
+ We could have a different resize multiple than 'resize now'
+ test multiple, but for now we don't do that.
+*/
+#define HT_MULTIPLE 8
+
+/* Copy the old entries, updating each to be in
+ a new list. Don't delete anything. Leave the
+ htin with stale data. */
+static void
+copy_abbrev_table_to_new_table(Dwarf_Hash_Table htin,
+ Dwarf_Hash_Table htout)
+{
+ Dwarf_Hash_Table_Entry entry_in = htin->tb_entries;
+ unsigned entry_in_count = htin->tb_table_entry_count;
+ Dwarf_Hash_Table_Entry entry_out = htout->tb_entries;
+ unsigned entry_out_count = htout->tb_table_entry_count;
+ unsigned k = 0;
+ for ( ; k < entry_in_count; ++k,++entry_in) {
+ Dwarf_Abbrev_List listent = entry_in->at_head;
+ Dwarf_Abbrev_List nextlistent = 0;
+
+ for ( ; listent ; listent = nextlistent) {
+ unsigned newtmp = listent->ab_code;
+ unsigned newhash = newtmp%entry_out_count;
+ Dwarf_Hash_Table_Entry e;
+ nextlistent = listent->ab_next;
+ e = entry_out+newhash;
+ /* Move_entry_to_new_hash. This reverses the
+ order of the entries, effectively, but
+ that does not seem significant. */
+ listent->ab_next = e->at_head;
+ e->at_head = listent;
+
+ htout->tb_total_abbrev_count++;
+ }
+ }
+}
+
+/*
+ This function returns a pointer to a Dwarf_Abbrev_List_s
+ struct for the abbrev with the given code. It puts the
+ struct on the appropriate hash table. It also adds all
+ the abbrev between the last abbrev added and this one to
+ the hash table. In other words, the .debug_abbrev section
+ is scanned sequentially from the top for an abbrev with
+ the given code. All intervening abbrevs are also put
+ into the hash table.
+
+ This function hashes the given code, and checks the chain
+ at that hash table entry to see if a Dwarf_Abbrev_List_s
+ with the given code exists. If yes, it returns a pointer
+ to that struct. Otherwise, it scans the .debug_abbrev
+ section from the last byte scanned for that CU till either
+ an abbrev with the given code is found, or an abbrev code
+ of 0 is read. It puts Dwarf_Abbrev_List_s entries for all
+ abbrev's read till that point into the hash table. The
+ hash table contains both a head pointer and a tail pointer
+ for each entry.
+
+ While the lists can move and entries can be moved between
+ lists on reallocation, any given Dwarf_Abbrev_list entry
+ never moves once allocated, so the pointer is safe to return.
+
+ Returns NULL on error.
+*/
+Dwarf_Abbrev_List
+_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code)
+{
+ Dwarf_Debug dbg = cu_context->cc_dbg;
+ Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table;
+ Dwarf_Hash_Table_Entry entry_base = 0;
+ Dwarf_Hash_Table_Entry entry_cur = 0;
+ Dwarf_Word hash_num = 0;
+ Dwarf_Unsigned abbrev_code = 0;
+ Dwarf_Unsigned abbrev_tag = 0;
+ Dwarf_Unsigned attr_name = 0;
+ Dwarf_Unsigned attr_form = 0;
+
+ Dwarf_Abbrev_List hash_abbrev_entry = 0;
+
+ Dwarf_Abbrev_List inner_list_entry = 0;
+ Dwarf_Hash_Table_Entry inner_hash_entry = 0;
+
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ unsigned hashable_val;
+
+ if ( !hash_table_base->tb_entries ) {
+ hash_table_base->tb_table_entry_count = HT_MULTIPLE;
+ hash_table_base->tb_total_abbrev_count= 0;
+ hash_table_base->tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ hash_table_base->tb_table_entry_count);
+ if(! hash_table_base->tb_entries) {
+ return NULL;
+ }
+
+ } else if (hash_table_base->tb_total_abbrev_count >
+ ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) {
+ struct Dwarf_Hash_Table_s newht;
+ /* Effectively multiplies by >= HT_MULTIPLE */
+ newht.tb_table_entry_count = hash_table_base->tb_total_abbrev_count;
+ newht.tb_total_abbrev_count = 0;
+ newht.tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ newht.tb_table_entry_count);
+
+ if(! newht.tb_entries) {
+ return NULL;
+ }
+ /* Copy the existing entries to the new table,
+ rehashing each.
+ */
+ copy_abbrev_table_to_new_table(hash_table_base, &newht);
+ /* Dealloc only the entries hash table array, not the lists
+ of things pointed to by a hash table entry array. */
+ dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+ hash_table_base->tb_entries = 0;
+ /* Now overwrite the existing table descriptor with
+ the new, newly valid, contents. */
+ *hash_table_base = newht;
+ } /* Else is ok as is, add entry */
+
+
+ hashable_val = code;
+ hash_num = hashable_val %
+ hash_table_base->tb_table_entry_count;
+ entry_base = hash_table_base->tb_entries;
+ entry_cur = entry_base + hash_num;
+
+ /* Determine if the 'code' is the list of synonyms already. */
+ for (hash_abbrev_entry = entry_cur->at_head;
+ hash_abbrev_entry != NULL && hash_abbrev_entry->ab_code != code;
+ hash_abbrev_entry = hash_abbrev_entry->ab_next);
+ if (hash_abbrev_entry != NULL) {
+ /* This returns a pointer to an abbrev list entry, not
+ the list itself. */
+ return (hash_abbrev_entry);
+ }
+
+ abbrev_ptr = cu_context->cc_last_abbrev_ptr != NULL ?
+ cu_context->cc_last_abbrev_ptr :
+ dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset;
+
+ /* End of abbrev's for this cu, since abbrev code is 0. */
+ if (*abbrev_ptr == 0) {
+ return (NULL);
+ }
+
+ do {
+ unsigned new_hashable_val;
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code);
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag);
+
+ inner_list_entry = (Dwarf_Abbrev_List)
+ _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
+ if (inner_list_entry == NULL)
+ return (NULL);
+
+ new_hashable_val = abbrev_code;
+ hash_num = new_hashable_val %
+ hash_table_base->tb_table_entry_count;
+ inner_hash_entry = entry_base + hash_num;
+ /* Move_entry_to_new_hash */
+ inner_list_entry->ab_next = inner_hash_entry->at_head;
+ inner_hash_entry->at_head = inner_list_entry;
+
+ hash_table_base->tb_total_abbrev_count++;
+
+ inner_list_entry->ab_code = abbrev_code;
+ inner_list_entry->ab_tag = abbrev_tag;
+ inner_list_entry->ab_has_child = *(abbrev_ptr++);
+ inner_list_entry->ab_abbrev_ptr = abbrev_ptr;
+
+ /* Cycle thru the abbrev content, ignoring the content except
+ to find the end of the content. */
+ do {
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_name);
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_form);
+ } while (attr_name != 0 && attr_form != 0);
+
+ } while (*abbrev_ptr != 0 && abbrev_code != code);
+
+ cu_context->cc_last_abbrev_ptr = abbrev_ptr;
+ return (abbrev_code == code ? inner_list_entry : NULL);
+}
+
+
+/* return 1 if string ends before 'endptr' else
+** return 0 meaning string is not properly terminated.
+** Presumption is the 'endptr' pts to end of some dwarf section data.
+*/
+int
+_dwarf_string_valid(void *startptr, void *endptr)
+{
+
+ char *start = startptr;
+ char *end = endptr;
+
+ while (start < end) {
+ if (*start == 0) {
+ return 1; /* OK! */
+ }
+ ++start;
+ ++end;
+ }
+ return 0; /* FAIL! bad string! */
+}
+
+/*
+ A byte-swapping version of memcpy
+ for cross-endian use.
+ Only 2,4,8 should be lengths passed in.
+*/
+void *
+_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len)
+{
+ void *orig_s1 = s1;
+ unsigned char *targ = (unsigned char *) s1;
+ unsigned char *src = (unsigned char *) s2;
+
+ if (len == 4) {
+ targ[3] = src[0];
+ targ[2] = src[1];
+ targ[1] = src[2];
+ targ[0] = src[3];
+ } else if (len == 8) {
+ targ[7] = src[0];
+ targ[6] = src[1];
+ targ[5] = src[2];
+ targ[4] = src[3];
+ targ[3] = src[4];
+ targ[2] = src[5];
+ targ[1] = src[6];
+ targ[0] = src[7];
+ } else if (len == 2) {
+ targ[1] = src[0];
+ targ[0] = src[1];
+ }
+/* should NOT get below here: is not the intended use */
+ else if (len == 1) {
+ targ[0] = src[0];
+ } else {
+ memcpy(s1, s2, len);
+ }
+
+ return orig_s1;
+}
+
+
+/*
+ This calculation used to be sprinkled all over.
+ Now brought to one place.
+
+ We try to accurately compute the size of a cu header
+ given a known cu header location ( an offset in .debug_info).
+
+*/
+/* ARGSUSED */
+Dwarf_Unsigned
+_dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset)
+{
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small *cuptr = dbg->de_debug_info.dss_data + offset;
+
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ cuptr, local_length_size, local_extension_size);
+
+ return local_extension_size + /* initial extesion, if present
+ */
+ local_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ local_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
+
+}
+
+/*
+ Pretend we know nothing about the CU
+ and just roughly compute the result.
+*/
+Dwarf_Unsigned
+_dwarf_length_of_cu_header_simple(Dwarf_Debug dbg)
+{
+ return dbg->de_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ dbg->de_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
+}
+
+/* Now that we delay loading .debug_info, we need to do the
+ load in more places. So putting the load
+ code in one place now instead of replicating it in multiple
+ places.
+
+*/
+int
+_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+
+ /* Testing de_debug_info.dss_data allows us to avoid testing
+ de_debug_abbrev.dss_data.
+ One test instead of 2. .debug_info is useless
+ without .debug_abbrev. */
+ if (dbg->de_debug_info.dss_data) {
+ return DW_DLV_OK;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ res = _dwarf_load_section(dbg, &dbg->de_debug_info, error);
+ return res;
+
+}
+void
+_dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,Dwarf_Hash_Table hash_table)
+{
+ /* A Hash Table is an array with tb_table_entry_count struct
+ Dwarf_Hash_Table_s entries in the array. */
+ int hashnum = 0;
+ for (; hashnum < hash_table->tb_table_entry_count; ++hashnum) {
+ struct Dwarf_Abbrev_List_s *abbrev = 0;
+ struct Dwarf_Abbrev_List_s *nextabbrev = 0;
+ struct Dwarf_Hash_Table_Entry_s *tb = &hash_table->tb_entries[hashnum];
+
+ abbrev = tb->at_head;
+ for (; abbrev; abbrev = nextabbrev) {
+ nextabbrev = abbrev->ab_next;
+ dwarf_dealloc(dbg, abbrev, DW_DLA_ABBREV_LIST);
+ }
+ }
+ /* Frees all the entries at once: an array. */
+ dwarf_dealloc(dbg,hash_table->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+}
+
+/*
+ If no die provided the size value returned might be wrong.
+ If different compilation units have different address sizes
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the Elf offset size != address_size
+ (for example if address_size = 4 but recorded in elf64 object)
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the die pointer is non-NULL (in which case it must point to
+ a valid DIE) this will return the correct size.
+*/
+int
+_dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die)
+{
+ Dwarf_CU_Context context = 0;
+ Dwarf_Half addrsize = 0;
+ if(!die) {
+ return dbg->de_pointer_size;
+ }
+ context = die->di_cu_context;
+ addrsize = context->cc_address_size;
+ return addrsize;
+}
+
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_util.h b/usr/src/lib/libdwarf/common/dwarf_util.h
new file mode 100644
index 0000000000..4046bb2478
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_util.h
@@ -0,0 +1,311 @@
+#ifndef DWARF_UTIL_H
+#define DWARF_UTIL_H
+/*
+
+ Copyright (C) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+/*
+ Decodes unsigned leb128 encoded numbers.
+ Make sure ptr is a pointer to a 1-byte type.
+ In 2003 and earlier this was a hand-inlined
+ version of _dwarf_decode_u_leb128() which did
+ not work correctly if Dwarf_Word was 64 bits.
+*/
+#define DECODE_LEB128_UWORD(ptr, value) \
+ do { \
+ Dwarf_Word uleblen; \
+ value = _dwarf_decode_u_leb128(ptr,&uleblen); \
+ ptr += uleblen; \
+ } while (0)
+
+/*
+ Decodes signed leb128 encoded numbers.
+ Make sure ptr is a pointer to a 1-byte type.
+ In 2003 and earlier this was a hand-inlined
+ version of _dwarf_decode_s_leb128() which did
+ not work correctly if Dwarf_Word was 64 bits.
+
+*/
+#define DECODE_LEB128_SWORD(ptr, value) \
+ do { \
+ Dwarf_Word sleblen; \
+ value = _dwarf_decode_s_leb128(ptr,&sleblen); \
+ ptr += sleblen; \
+ } while(0)
+
+
+/*
+ Skips leb128_encoded numbers that are guaranteed
+ to be no more than 4 bytes long. Same for both
+ signed and unsigned numbers.
+*/
+#define SKIP_LEB128_WORD(ptr) \
+ do{ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ } \
+ } \
+ } \
+ } } while (0)
+
+
+#define CHECK_DIE(die, error_ret_value) \
+do {if (die == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DIE_NULL); \
+ return(error_ret_value); \
+ } \
+ if (die->di_cu_context == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DIE_NO_CU_CONTEXT); \
+ return(error_ret_value); \
+ } \
+ if (die->di_cu_context->cc_dbg == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL); \
+ return(error_ret_value); \
+ } \
+} while (0)
+
+
+/*
+ Reads 'source' for 'length' bytes from unaligned addr.
+
+ Avoids any constant-in-conditional warnings and
+ avoids a test in the generated code (for non-const cases,
+ which are in the majority.)
+ Uses a temp to avoid the test.
+ The decl here should avoid any problem of size in the temp.
+ This code is ENDIAN DEPENDENT
+ The memcpy args are the endian issue.
+*/
+typedef Dwarf_Unsigned BIGGEST_UINT;
+
+#ifdef WORDS_BIGENDIAN
+#define READ_UNALIGNED(dbg,dest,desttype, source, length) \
+ do { \
+ BIGGEST_UINT _ltmp = 0; \
+ dbg->de_copy_word( (((char *)(&_ltmp)) + sizeof(_ltmp) - length), \
+ source, length) ; \
+ dest = (desttype)_ltmp; \
+ } while (0)
+
+
+/*
+ This macro sign-extends a variable depending on the length.
+ It fills the bytes between the size of the destination and
+ the length with appropriate padding.
+ This code is ENDIAN DEPENDENT but dependent only
+ on host endianness, not object file endianness.
+ The memcpy args are the issue.
+*/
+#define SIGN_EXTEND(dest, length) \
+ do {if (*(Dwarf_Sbyte *)((char *)&dest + sizeof(dest) - length) < 0) {\
+ memcpy((char *)&dest, "\xff\xff\xff\xff\xff\xff\xff\xff", \
+ sizeof(dest) - length); \
+ } \
+ } while (0)
+#else /* LITTLE ENDIAN */
+
+#define READ_UNALIGNED(dbg,dest,desttype, source, length) \
+ do { \
+ BIGGEST_UINT _ltmp = 0; \
+ dbg->de_copy_word( (char *)(&_ltmp) , \
+ source, length) ; \
+ dest = (desttype)_ltmp; \
+ } while (0)
+
+
+/*
+ This macro sign-extends a variable depending on the length.
+ It fills the bytes between the size of the destination and
+ the length with appropriate padding.
+ This code is ENDIAN DEPENDENT but dependent only
+ on host endianness, not object file endianness.
+ The memcpy args are the issue.
+*/
+#define SIGN_EXTEND(dest, length) \
+ do {if (*(Dwarf_Sbyte *)((char *)&dest + (length-1)) < 0) {\
+ memcpy((char *)&dest+length, \
+ "\xff\xff\xff\xff\xff\xff\xff\xff", \
+ sizeof(dest) - length); \
+ } \
+ } while (0)
+
+#endif /* ! LITTLE_ENDIAN */
+
+
+
+/*
+ READ_AREA LENGTH reads the length (the older way
+ of pure 32 or 64 bit
+ or the new proposed dwarfv2.1 64bit-extension way)
+
+ It reads the bits from where rw_src_data_p points to
+ and updates the rw_src_data_p to point past what was just read.
+
+ It updates w_length_size (to the size of an offset, either 4 or 8)
+ and w_exten_size (set 0 unless this frame has the DWARF3,4 64bit
+ extension, in which case w_exten_size is set to 4).
+
+ r_dbg is just the current dbg pointer.
+ w_target is the output length field.
+ r_targtype is the output type. Always Dwarf_Unsigned so far.
+
+*/
+/* This one handles the v2.1 64bit extension
+ and 32bit (and MIPS fixed 64 bit via the
+ dwarf_init-set r_dbg->de_length_size)..
+ It does not recognize any but the one distingushed value
+ (the only one with defined meaning).
+ It assumes that no CU will have a length
+ 0xffffffxx (32bit length)
+ or
+ 0xffffffxx xxxxxxxx (64bit length)
+ which makes possible auto-detection of the extension.
+
+ This depends on knowing that only a non-zero length
+ is legitimate (AFAICT), and for IRIX non-standard -64
+ dwarf that the first 32 bits of the 64bit offset will be
+ zero (because the compiler could not handle a truly large
+ value as of Jan 2003 and because no app has that much debug
+ info anyway, at least not in the IRIX case).
+
+ At present not testing for '64bit elf' here as that
+ does not seem necessary (none of the 64bit length seems
+ appropriate unless it's ident[EI_CLASS] == ELFCLASS64).
+*/
+# define READ_AREA_LENGTH(r_dbg,w_target,r_targtype, \
+ rw_src_data_p,w_length_size,w_exten_size) \
+do { READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, ORIGINAL_DWARF_OFFSET_SIZE); \
+ if(w_target == DISTINGUISHED_VALUE) { \
+ /* dwarf3 64bit extension */ \
+ w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ rw_src_data_p += ORIGINAL_DWARF_OFFSET_SIZE; \
+ w_exten_size = ORIGINAL_DWARF_OFFSET_SIZE; \
+ READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE);\
+ rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ } else { \
+ if(w_target == 0 && r_dbg->de_big_endian_object) { \
+ /* IRIX 64 bit, big endian. This test */ \
+ /* is not a truly precise test, a precise test */ \
+ /* would check if the target was IRIX. */ \
+ READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE); \
+ w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ w_exten_size = 0; \
+ } else { \
+ /* standard 32 bit dwarf2/dwarf3 */ \
+ w_exten_size = 0; \
+ w_length_size = ORIGINAL_DWARF_OFFSET_SIZE; \
+ rw_src_data_p += w_length_size; \
+ } \
+ } } while(0)
+
+Dwarf_Unsigned
+_dwarf_decode_u_leb128(Dwarf_Small * leb128,
+ Dwarf_Word * leb128_length);
+
+Dwarf_Signed
+_dwarf_decode_s_leb128(Dwarf_Small * leb128,
+ Dwarf_Word * leb128_length);
+
+Dwarf_Unsigned
+_dwarf_get_size_of_val(Dwarf_Debug dbg,
+ Dwarf_Unsigned form,
+ Dwarf_Half address_size,
+ Dwarf_Small * val_ptr,
+ int v_length_size);
+
+struct Dwarf_Hash_Table_Entry_s;
+/* This single struct is the base for the hash table.
+ The intent is that once the total_abbrev_count across
+ all the entries is greater than 10*current_table_entry_count
+ one should build a new Dwarf_Hash_Table_Base_s, rehash
+ all the existing entries, and delete the old table and entries.
+ (10 is a heuristic, nothing magic about it, but once the
+ count gets to 30 or 40 times current_table_entry_count
+ things really slow down a lot. One (500MB) application had
+ 127000 abbreviations in one compilation unit)
+ The incoming 'code' is an abbrev number and those simply
+ increase linearly so the hashing is perfect always.
+*/
+struct Dwarf_Hash_Table_s {
+ unsigned long tb_table_entry_count;
+ unsigned long tb_total_abbrev_count;
+ /* Each table entry is a list of abbreviations. */
+ struct Dwarf_Hash_Table_Entry_s *tb_entries;
+};
+
+/*
+ This struct is used to build a hash table for the
+ abbreviation codes for a compile-unit.
+*/
+struct Dwarf_Hash_Table_Entry_s {
+ Dwarf_Abbrev_List at_head;
+};
+
+
+
+Dwarf_Abbrev_List
+_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context,
+ Dwarf_Unsigned code);
+
+
+/* return 1 if string ends before 'endptr' else
+** return 0 meaning string is not properly terminated.
+** Presumption is the 'endptr' pts to end of some dwarf section data.
+*/
+int _dwarf_string_valid(void *startptr, void *endptr);
+
+Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug,
+ Dwarf_Unsigned offset);
+Dwarf_Unsigned _dwarf_length_of_cu_header_simple(Dwarf_Debug);
+
+int _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error *error);
+void _dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,
+ struct Dwarf_Hash_Table_s* hash_table);
+int _dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die);
+
+#endif /* DWARF_UTIL_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_vars.c b/usr/src/lib/libdwarf/common/dwarf_vars.c
new file mode 100644
index 0000000000..24105289ba
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_vars.c
@@ -0,0 +1,133 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_vars.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_vars(Dwarf_Debug dbg,
+ Dwarf_Var ** vars,
+ Dwarf_Signed * ret_var_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_varnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_varnames.dss_data,
+ dbg->de_debug_varnames.dss_size,
+ (Dwarf_Global **) vars, /* Type punning for sections
+ with identical format. */
+ ret_var_count,
+ error,
+ DW_DLA_VAR_CONTEXT,
+ DW_DLA_VAR,
+ DW_DLE_DEBUG_VARNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_VARNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_vars_dealloc(Dwarf_Debug dbg, Dwarf_Var * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_VAR_CONTEXT,
+ DW_DLA_VAR, DW_DLA_LIST);
+ return;
+}
+
+
+int
+dwarf_varname(Dwarf_Var var_in, char **ret_varname, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ if (var == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_VAR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_varname = (char *) (var->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_var_die_offset(Dwarf_Var var_in,
+ Dwarf_Off * returned_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return dwarf_global_die_offset(var, returned_offset, error);
+
+}
+
+
+int
+dwarf_var_cu_offset(Dwarf_Var var_in,
+ Dwarf_Off * returned_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return dwarf_global_cu_offset(var, returned_offset, error);
+}
+
+
+int
+dwarf_var_name_offsets(Dwarf_Var var_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return
+ dwarf_global_name_offsets(var,
+ returned_name, die_offset, cu_offset,
+ error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_vars.h b/usr/src/lib/libdwarf/common/dwarf_vars.h
new file mode 100644
index 0000000000..bd5f967e48
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_vars.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+typedef struct Dwarf_Var_Context_s *Dwarf_Var_Context;
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_weaks.c b/usr/src/lib/libdwarf/common/dwarf_weaks.c
new file mode 100644
index 0000000000..425916e62e
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_weaks.c
@@ -0,0 +1,130 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_weaks.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_weaks(Dwarf_Debug dbg,
+ Dwarf_Weak ** weaks,
+ Dwarf_Signed * ret_weak_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_weaknames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_weaknames.dss_data,
+ dbg->de_debug_weaknames.dss_size,
+ (Dwarf_Global **) weaks, /* Type punning for sections
+ with identical format. */
+ ret_weak_count,
+ error,
+ DW_DLA_WEAK_CONTEXT,
+ DW_DLA_WEAK,
+ DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_weaks_dealloc(Dwarf_Debug dbg, Dwarf_Weak * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_WEAK_CONTEXT,
+ DW_DLA_WEAK, DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_weakname(Dwarf_Weak weak_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ if (weak == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_WEAK_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *ret_name = (char *) (weak->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_weak_die_offset(Dwarf_Weak weak_in,
+ Dwarf_Off * weak_off, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_die_offset(weak, weak_off, error);
+}
+
+
+int
+dwarf_weak_cu_offset(Dwarf_Weak weak_in,
+ Dwarf_Off * weak_off, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_cu_offset(weak, weak_off, error);
+}
+
+
+int
+dwarf_weak_name_offsets(Dwarf_Weak weak_in,
+ char **weak_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_offset, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_name_offsets(weak,
+ weak_name, die_offset, cu_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_weaks.h b/usr/src/lib/libdwarf/common/dwarf_weaks.h
new file mode 100644
index 0000000000..d38f5f118a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_weaks.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+typedef struct Dwarf_Weak_Context_s *Dwarf_Weak_Context;
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/libdwarf.h b/usr/src/lib/libdwarf/common/libdwarf.h
new file mode 100644
index 0000000000..78627a96a6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/libdwarf.h
@@ -0,0 +1,2736 @@
+/*
+
+ Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#ifndef _LIBDWARF_H
+#define _LIBDWARF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ libdwarf.h
+ $Revision: #9 $ $Date: 2008/01/17 $
+
+ For libdwarf producers and consumers
+
+ The interface is defined as having 8-byte signed and unsigned
+ values so it can handle 64-or-32bit target on 64-or-32bit host.
+ Addr is the native size: it represents pointers on
+ the host machine (not the target!).
+
+ This contains declarations for types and all producer
+ and consumer functions.
+
+ Function declarations are written on a single line each here
+ so one can use grep to each declaration in its entirety.
+ The declarations are a little harder to read this way, but...
+
+*/
+
+struct Elf;
+typedef struct Elf* dwarf_elf_handle;
+
+/* To enable printing with printf regardless of the
+ actual underlying data type, we define the DW_PR_xxx macros. */
+#if (_MIPS_SZLONG == 64)
+/* Special case for MIPS, so -64 (LP64) build gets simple -long-.
+ Non-MIPS LP64 or ILP64 environments should probably ensure
+ _MIPS_SZLONG set to 64 everywhere this header is #included.
+*/
+typedef int Dwarf_Bool; /* boolean type */
+typedef unsigned long Dwarf_Off; /* 4 or 8 byte file offset */
+typedef unsigned long Dwarf_Unsigned; /* 4 or 8 byte unsigned value */
+typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */
+typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */
+typedef signed long Dwarf_Signed; /* 4 or 8 byte signed value */
+typedef unsigned long Dwarf_Addr; /* target memory address */
+#define DW_PR_DUx "lx"
+#define DW_PR_DSx "lx"
+#define DW_PR_DUu "lu"
+#define DW_PR_DSd "ld"
+
+#else /* 32-bit */
+/* This is for ILP32, allowing i/o of 64bit dwarf info.
+ Also should be fine for LP64 and ILP64 cases.
+*/
+typedef int Dwarf_Bool; /* boolean type */
+typedef unsigned long long Dwarf_Off; /* 8 byte file offset */
+typedef unsigned long long Dwarf_Unsigned; /* 8 byte unsigned value*/
+typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */
+typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */
+typedef signed long long Dwarf_Signed; /* 8 byte signed value */
+typedef unsigned long long Dwarf_Addr; /* target memory address */
+#define DW_PR_DUx "llx"
+#define DW_PR_DSx "llx"
+#define DW_PR_DUu "llu"
+#define DW_PR_DSd "lld"
+#endif
+#ifdef HAVE_NONSTANDARD_PRINTF_64_FORMAT
+/* Windows does not use std C formatting, so allow it. */
+#undef DW_PR_DUx
+#undef DW_PR_DSx
+#undef DW_PR_DUu
+#undef DW_PR_DSd
+#define DW_PR_DUx "I64x"
+#define DW_PR_DSx "I64x"
+#define DW_PR_DUu "I64u"
+#define DW_PR_DSd "I64d"
+#endif /* HAVE_NONSTANDARD_FORMAT */
+
+typedef void* Dwarf_Ptr; /* host machine pointer */
+
+/* Used for DW_FORM_ref_sig8. It is not a string, it
+ is 8 bytes of a signature one would use to find
+ a type unit. See dwarf_formsig8()
+*/
+typedef struct {
+ char signature[8];
+} Dwarf_Sig8;
+
+/* Contains info on an uninterpreted block of data
+*/
+typedef struct {
+ Dwarf_Unsigned bl_len; /* length of block */
+ Dwarf_Ptr bl_data; /* uninterpreted data */
+ Dwarf_Small bl_from_loclist; /*non-0 if loclist, else debug_info*/
+ Dwarf_Unsigned bl_section_offset; /* Section (not CU) offset
+ which 'data' comes from. */
+} Dwarf_Block;
+
+
+/* location record
+*/
+typedef struct {
+ Dwarf_Small lr_atom; /* location operation */
+ Dwarf_Unsigned lr_number; /* operand */
+ Dwarf_Unsigned lr_number2; /* for OP_BREGx */
+ Dwarf_Unsigned lr_offset; /* offset in locexpr for OP_BRA etc */
+} Dwarf_Loc;
+
+
+/* location description
+*/
+typedef struct {
+ Dwarf_Addr ld_lopc; /* beginning of active range */
+ Dwarf_Addr ld_hipc; /* end of active range */
+ Dwarf_Half ld_cents; /* count of location records */
+ Dwarf_Loc* ld_s; /* pointer to list of same */
+ Dwarf_Small ld_from_loclist;
+ /* non-0 if loclist, else debug_info*/
+
+ Dwarf_Unsigned ld_section_offset; /* Section (not CU) offset
+ where loc-expr begins*/
+} Dwarf_Locdesc;
+
+/* First appears in DWARF3.
+ The dwr_addr1/addr2 data is either an offset (DW_RANGES_ENTRY)
+ or an address (dwr_addr2 in DW_RANGES_ADDRESS_SELECTION) or
+ both are zero (DW_RANGES_END).
+*/
+enum Dwarf_Ranges_Entry_Type { DW_RANGES_ENTRY,
+ DW_RANGES_ADDRESS_SELECTION,
+ DW_RANGES_END };
+typedef struct {
+ Dwarf_Addr dwr_addr1;
+ Dwarf_Addr dwr_addr2;
+ enum Dwarf_Ranges_Entry_Type dwr_type;
+} Dwarf_Ranges;
+
+/* Frame description instructions expanded.
+*/
+typedef struct {
+ Dwarf_Small fp_base_op;
+ Dwarf_Small fp_extended_op;
+ Dwarf_Half fp_register;
+
+ /* Value may be signed, depends on op.
+ Any applicable data_alignment_factor has
+ not been applied, this is the raw offset. */
+ Dwarf_Unsigned fp_offset;
+ Dwarf_Off fp_instr_offset;
+} Dwarf_Frame_Op; /* DWARF2 */
+
+typedef struct {
+ Dwarf_Small fp_base_op;
+ Dwarf_Small fp_extended_op;
+ Dwarf_Half fp_register;
+
+ /* Value may be signed, depends on op.
+ Any applicable data_alignment_factor has
+ not been applied, this is the raw offset. */
+ Dwarf_Unsigned fp_offset_or_block_len;
+ Dwarf_Small *fp_expr_block;
+
+ Dwarf_Off fp_instr_offset;
+} Dwarf_Frame_Op3; /* DWARF3 and DWARF2 compatible */
+
+/* ***IMPORTANT NOTE, TARGET DEPENDENCY ****
+ DW_REG_TABLE_SIZE must be at least as large as
+ the number of registers
+ (DW_FRAME_LAST_REG_NUM) as defined in dwarf.h
+ Preferably identical to DW_FRAME_LAST_REG_NUM.
+ Ensure [0-DW_REG_TABLE_SIZE] does not overlap
+ DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL.
+ Also ensure DW_FRAME_REG_INITIAL_VALUE is set to what
+ is appropriate to your cpu.
+ For various CPUs DW_FRAME_UNDEFINED_VAL is correct
+ as the value for DW_FRAME_REG_INITIAL_VALUE.
+
+ For consumer apps, this can be set dynamically: see
+ dwarf_set_frame_rule_table_size();
+ */
+#ifndef DW_REG_TABLE_SIZE
+#define DW_REG_TABLE_SIZE 66
+#endif
+
+/* For MIPS, DW_FRAME_SAME_VAL is the correct default value
+ for a frame register value. For other CPUS another value
+ may be better, such as DW_FRAME_UNDEFINED_VAL.
+ See dwarf_set_frame_rule_table_size
+*/
+#ifndef DW_FRAME_REG_INITIAL_VALUE
+#define DW_FRAME_REG_INITIAL_VALUE DW_FRAME_SAME_VAL
+#endif
+
+/* Taken as meaning 'undefined value', this is not
+ a column or register number.
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+*/
+#define DW_FRAME_UNDEFINED_VAL 1034
+
+/* Taken as meaning 'same value' as caller had, not a column
+ or register number.
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+*/
+#define DW_FRAME_SAME_VAL 1035
+
+/* For DWARF3 consumer interfaces, make the CFA a column with no
+ real table number. This is what should have been done
+ for the DWARF2 interfaces. This actually works for
+ both DWARF2 and DWARF3, but see the libdwarf documentation
+ on Dwarf_Regtable3 and dwarf_get_fde_info_for_reg3()
+ and dwarf_get_fde_info_for_all_regs3()
+ Do NOT use this with the older dwarf_get_fde_info_for_reg()
+ or dwarf_get_fde_info_for_all_regs() consumer interfaces.
+ Must be higher than any register count for *any* ABI
+ (ensures maximum applicability with minimum effort).
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+*/
+#define DW_FRAME_CFA_COL3 1436
+
+/* The following are all needed to evaluate DWARF3 register rules.
+*/
+#define DW_EXPR_OFFSET 0 /* DWARF2 only sees this. */
+#define DW_EXPR_VAL_OFFSET 1
+#define DW_EXPR_EXPRESSION 2
+#define DW_EXPR_VAL_EXPRESSION 3
+
+typedef struct Dwarf_Regtable_Entry_s {
+ /* For each index i (naming a hardware register with dwarf number
+ i) the following is true and defines the value of that register:
+
+ If dw_regnum is Register DW_FRAME_UNDEFINED_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has no defined value.
+ If dw_regnum is Register DW_FRAME_SAME_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has the same
+ value in the previous frame.
+ DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL are
+ only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+
+ Otherwise: the register number is a DWARF register number
+ (see ABI documents for how this translates to hardware/
+ software register numbers in the machine hardware)
+ and the following applies:
+
+ if dw_value_type == DW_EXPR_OFFSET (the only case for dwarf2):
+ If dw_offset_relevant is non-zero, then
+ the value is stored at at the address CFA+N where
+ N is a signed offset.
+ Rule: Offset(N)
+ If dw_offset_relevant is zero, then the value of the register
+ is the value of (DWARF) register number dw_regnum.
+ Rule: register(F)
+ Other values of dw_value_type are an error.
+ */
+ Dwarf_Small dw_offset_relevant;
+
+ /* For DWARF2, always 0 */
+ Dwarf_Small dw_value_type;
+
+ Dwarf_Half dw_regnum;
+
+ /* The data type here should the larger of Dwarf_Addr
+ and Dwarf_Unsigned and Dwarf_Signed. */
+ Dwarf_Addr dw_offset;
+} Dwarf_Regtable_Entry;
+
+typedef struct Dwarf_Regtable_s {
+ struct Dwarf_Regtable_Entry_s rules[DW_REG_TABLE_SIZE];
+} Dwarf_Regtable;
+
+/* opaque type. Functional interface shown later. */
+struct Dwarf_Reg_value3_s;
+typedef struct Dwarf_Reg_value3_s Dwarf_Reg_Value3;
+
+typedef struct Dwarf_Regtable_Entry3_s {
+ /* For each index i (naming a hardware register with dwarf number
+ i) the following is true and defines the value of that register:
+
+ If dw_regnum is Register DW_FRAME_UNDEFINED_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has no defined value.
+ If dw_regnum is Register DW_FRAME_SAME_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has the same
+ value in the previous frame.
+ DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL and
+ DW_FRAME_CFA_COL3 are only present at libdwarf runtime.
+ Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Because DW_FRAME_SAME_VAL and DW_FRAME_UNDEFINED_VAL
+ and DW_FRAME_CFA_COL3 are defineable at runtime
+ consider the names symbolic in this comment, not absolute.
+
+ Otherwise: the register number is a DWARF register number
+ (see ABI documents for how this translates to hardware/
+ software register numbers in the machine hardware)
+ and the following applies:
+
+ In a cfa-defining entry (rt3_cfa_rule) the regnum is the
+ CFA 'register number'. Which is some 'normal' register,
+ not DW_FRAME_CFA_COL3, nor DW_FRAME_SAME_VAL, nor
+ DW_FRAME_UNDEFINED_VAL.
+
+ If dw_value_type == DW_EXPR_OFFSET (the only possible case for
+ dwarf2):
+ If dw_offset_relevant is non-zero, then
+ the value is stored at at the address
+ CFA+N where N is a signed offset.
+ dw_regnum is the cfa register rule which means
+ one ignores dw_regnum and uses the CFA appropriately.
+ So dw_offset_or_block_len is a signed value, really,
+ and must be printed/evaluated as such.
+ Rule: Offset(N)
+ If dw_offset_relevant is zero, then the value of the register
+ is the value of (DWARF) register number dw_regnum.
+ Rule: register(R)
+ If dw_value_type == DW_EXPR_VAL_OFFSET
+ the value of this register is CFA +N where N is a signed offset.
+ dw_regnum is the cfa register rule which means
+ one ignores dw_regnum and uses the CFA appropriately.
+ Rule: val_offset(N)
+ If dw_value_type == DW_EXPR_EXPRESSION
+ The value of the register is the value at the address
+ computed by evaluating the DWARF expression E.
+ Rule: expression(E)
+ The expression E byte stream is pointed to by dw_block_ptr.
+ The expression length in bytes is given by
+ dw_offset_or_block_len.
+ If dw_value_type == DW_EXPR_VAL_EXPRESSION
+ The value of the register is the value
+ computed by evaluating the DWARF expression E.
+ Rule: val_expression(E)
+ The expression E byte stream is pointed to by dw_block_ptr.
+ The expression length in bytes is given by
+ dw_offset_or_block_len.
+ Other values of dw_value_type are an error.
+ */
+ Dwarf_Small dw_offset_relevant;
+ Dwarf_Small dw_value_type;
+ Dwarf_Half dw_regnum;
+ Dwarf_Unsigned dw_offset_or_block_len;
+ Dwarf_Ptr dw_block_ptr;
+
+}Dwarf_Regtable_Entry3;
+
+/* For the DWARF3 version, moved the DW_FRAME_CFA_COL
+ out of the array and into its own struct.
+ Having it part of the array is not very easy to work
+ with from a portability point of view: changing
+ the number for every architecture is a pain (if one fails
+ to set it correctly a register rule gets clobbered when
+ setting CFA). With MIPS it just happened to be easy to use
+ DW_FRAME_CFA_COL (it was wrong conceptually but it was easy...).
+
+ rt3_rules and rt3_reg_table_size must be filled in before
+ calling libdwarf. Filled in with a pointer to an array
+ (pointer and array set up by the calling application)
+ of rt3_reg_table_size Dwarf_Regtable_Entry3_s structs.
+ libdwarf does not allocate or deallocate space for the
+ rules, you must do so. libdwarf will initialize the
+ contents rules array, you do not need to do so (though
+ if you choose to initialize the array somehow that is ok:
+ libdwarf will overwrite your initializations with its own).
+
+*/
+typedef struct Dwarf_Regtable3_s {
+ struct Dwarf_Regtable_Entry3_s rt3_cfa_rule;
+
+ Dwarf_Half rt3_reg_table_size;
+ struct Dwarf_Regtable_Entry3_s * rt3_rules;
+} Dwarf_Regtable3;
+
+
+/* Use for DW_EPXR_STANDARD., DW_EXPR_VAL_OFFSET.
+ Returns DW_DLV_OK if the value is available.
+ If DW_DLV_OK returns the regnum and offset thru the pointers
+ (which the consumer must use appropriately).
+*/
+int dwarf_frame_get_reg_register(struct Dwarf_Regtable_Entry3_s *reg_in,
+ Dwarf_Small *offset_relevant,
+ Dwarf_Half *regnum_out,
+ Dwarf_Signed *offset_out);
+
+/* Use for DW_EXPR_EXPRESSION, DW_EXPR_VAL_EXPRESSION.
+ Returns DW_DLV_OK if the value is available.
+ The caller must pass in the address of a valid
+ Dwarf_Block (the caller need not initialize it).
+*/
+int dwarf_frame_get_reg_expression(struct Dwarf_Regtable_Entry3_s *reg_in,
+ Dwarf_Block *block_out);
+
+
+/* For DW_DLC_SYMBOLIC_RELOCATIONS output to caller
+ v2, adding drd_length: some relocations are 4 and
+ some 8 bytes (pointers are 8, section offsets 4) in
+ some dwarf environments. (MIPS relocations are all one
+ size in any given ABI.) Changing drd_type to an unsigned char
+ to keep struct size down.
+*/
+enum Dwarf_Rel_Type {
+ dwarf_drt_none, /* Should not get to caller */
+ dwarf_drt_data_reloc, /* Simple normal relocation. */
+ dwarf_drt_segment_rel, /* Special reloc, exceptions. */
+ /* dwarf_drt_first_of_length_pair and drt_second
+ are for for the .word end - begin case. */
+ dwarf_drt_first_of_length_pair,
+ dwarf_drt_second_of_length_pair
+};
+
+typedef struct Dwarf_P_Marker_s * Dwarf_P_Marker;
+struct Dwarf_P_Marker_s {
+ Dwarf_Unsigned ma_marker;
+ Dwarf_Unsigned ma_offset;
+};
+
+typedef struct Dwarf_Relocation_Data_s * Dwarf_Relocation_Data;
+struct Dwarf_Relocation_Data_s {
+ unsigned char drd_type; /* Cast to/from Dwarf_Rel_Type
+ to keep size small in struct. */
+ unsigned char drd_length; /* Length in bytes of data being
+ relocated. 4 for 32bit data,
+ 8 for 64bit data. */
+ Dwarf_Unsigned drd_offset; /* Where the data to reloc is. */
+ Dwarf_Unsigned drd_symbol_index;
+};
+
+typedef struct Dwarf_P_String_Attr_s * Dwarf_P_String_Attr;
+struct Dwarf_P_String_Attr_s {
+ Dwarf_Unsigned sa_offset; /* Offset of string attribute data */
+ Dwarf_Unsigned sa_nbytes;
+};
+
+
+/* Opaque types for Consumer Library. */
+typedef struct Dwarf_Debug_s* Dwarf_Debug;
+typedef struct Dwarf_Die_s* Dwarf_Die;
+typedef struct Dwarf_Line_s* Dwarf_Line;
+typedef struct Dwarf_Global_s* Dwarf_Global;
+typedef struct Dwarf_Func_s* Dwarf_Func;
+typedef struct Dwarf_Type_s* Dwarf_Type;
+typedef struct Dwarf_Var_s* Dwarf_Var;
+typedef struct Dwarf_Weak_s* Dwarf_Weak;
+typedef struct Dwarf_Error_s* Dwarf_Error;
+typedef struct Dwarf_Attribute_s* Dwarf_Attribute;
+typedef struct Dwarf_Abbrev_s* Dwarf_Abbrev;
+typedef struct Dwarf_Fde_s* Dwarf_Fde;
+typedef struct Dwarf_Cie_s* Dwarf_Cie;
+typedef struct Dwarf_Arange_s* Dwarf_Arange;
+
+/* Opaque types for Producer Library. */
+typedef struct Dwarf_P_Debug_s* Dwarf_P_Debug;
+typedef struct Dwarf_P_Die_s* Dwarf_P_Die;
+typedef struct Dwarf_P_Attribute_s* Dwarf_P_Attribute;
+typedef struct Dwarf_P_Fde_s* Dwarf_P_Fde;
+typedef struct Dwarf_P_Expr_s* Dwarf_P_Expr;
+typedef Dwarf_Unsigned Dwarf_Tag;
+
+
+/* error handler function
+*/
+typedef void (*Dwarf_Handler)(Dwarf_Error /*error*/, Dwarf_Ptr /*errarg*/);
+
+
+/* Begin libdwarf Object File Interface declarations.
+
+As of February 2008 there are multiple dwarf_reader object access
+initialization methods available:
+The traditional dwarf_elf_init() and dwarf_init() and dwarf_finish()
+ which assume libelf and POSIX file access.
+An object-file and library agnostic dwarf_object_init() and dwarf_object_finish()
+ which allow the coder to provide object access routines
+ abstracting away the elf interface. So there is no dependence in the
+ reader code on the object format and no dependence on libelf.
+ See the code in dwarf_elf_access.c and dwarf_original_elf_init.c
+ to see an example of initializing the structures mentioned below.
+
+Projects using dwarf_elf_init() or dwarf_init() can ignore
+the Dwarf_Obj_Access* structures entirely as all these details
+are completed for you.
+
+*/
+
+typedef struct Dwarf_Obj_Access_Interface_s Dwarf_Obj_Access_Interface;
+typedef struct Dwarf_Obj_Access_Methods_s Dwarf_Obj_Access_Methods;
+typedef struct Dwarf_Obj_Access_Section_s Dwarf_Obj_Access_Section;
+
+
+/* Used in the get_section interface function
+ in Dwarf_Obj_Access_Section_s. Since libdwarf
+ depends on standard DWARF section names an object
+ format that has no such names (but has some
+ method of setting up 'sections equivalents')
+ must arrange to return standard DWARF section
+ names in the 'name' field. libdwarf does
+ not free the strings in 'name'. */
+struct Dwarf_Obj_Access_Section_s {
+ Dwarf_Addr addr;
+ Dwarf_Unsigned size;
+ const char* name;
+ /* Set link to zero if it is meaningless. If non-zero
+ it should be a link to a rela section or from symtab
+ to strtab. In Elf it is sh_link. */
+ Dwarf_Unsigned link;
+};
+
+/* Returned by the get_endianness function in
+ Dwarf_Obj_Access_Methods_s. */
+typedef enum {
+ DW_OBJECT_MSB,
+ DW_OBJECT_LSB
+} Dwarf_Endianness;
+
+/* The functions we need to access object data from libdwarf are declared here.
+
+ In these function pointer declarations
+ 'void *obj' is intended to be a pointer (the object field in
+ Dwarf_Obj_Access_Interface_s)
+ that hides the library-specific and object-specific data that makes
+ it possible to handle multiple object formats and multiple libraries.
+ It's not required that one handles multiple such in a single libdwarf
+ archive/shared-library (but not ruled out either).
+ See dwarf_elf_object_access_internals_t and dwarf_elf_access.c
+ for an example.
+
+*/
+struct Dwarf_Obj_Access_Methods_s {
+ /**
+ * get_section_info
+ *
+ * Get address, size, and name info about a section.
+ *
+ * Parameters
+ * section_index - Zero-based index.
+ * return_section - Pointer to a structure in which section info
+ * will be placed. Caller must provide a valid pointer to a
+ * structure area. The structure's contents will be overwritten
+ * by the call to get_section_info.
+ * error - A pointer to an integer in which an error code may be stored.
+ *
+ * Return
+ * DW_DLV_OK - Everything ok.
+ * DW_DLV_ERROR - Error occurred. Use 'error' to determine the
+ * libdwarf defined error.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*get_section_info)(void* obj, Dwarf_Half section_index,
+ Dwarf_Obj_Access_Section* return_section, int* error);
+ /**
+ * get_byte_order
+ *
+ * Get whether the object file represented by this interface is big-endian
+ * (DW_OBJECT_MSB) or little endian (DW_OBJECT_LSB).
+ *
+ * Parameters
+ * obj - Equivalent to 'this' in OO languages.
+ *
+ * Return
+ * Endianness of object. Cannot fail.
+ */
+ Dwarf_Endianness (*get_byte_order)(void* obj);
+ /**
+ * get_length_size
+ *
+ * Get the size of a length field in the underlying object file.
+ * libdwarf currently supports * 4 and 8 byte sizes, but may
+ * support larger in the future.
+ * Perhaps the return type should be an enumeration?
+ *
+ * Parameters
+ * obj - Equivalent to 'this' in OO languages.
+ *
+ * Return
+ * Size of length. Cannot fail.
+ */
+ Dwarf_Small (*get_length_size)(void* obj);
+ /**
+ * get_pointer_size
+ *
+ * Get the size of a pointer field in the underlying object file.
+ * libdwarf currently supports 4 and 8 byte sizes.
+ * Perhaps the return type should be an enumeration?
+
+ * Return
+ * Size of pointer. Cannot fail.
+ */
+ Dwarf_Small (*get_pointer_size)(void* obj);
+ /**
+ * get_section_count
+ *
+ * Get the number of sections in the object file.
+ *
+ * Parameters
+ *
+ * Return
+ * Number of sections
+ */
+ Dwarf_Unsigned (*get_section_count)(void* obj);
+ /**
+ * load_section
+ *
+ * Get a pointer to an array of bytes that represent the section.
+ *
+ * Parameters
+ * section_index - Zero-based index.
+ * return_data - The address of a pointer to which the section data block
+ * will be assigned.
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*load_section)(void* obj, Dwarf_Half section_index,
+ Dwarf_Small** return_data, int* error);
+
+ /**
+ * relocate_a_section
+ * If relocations are not supported leave this pointer NULL.
+ *
+ * Get a pointer to an array of bytes that represent the section.
+ *
+ * Parameters
+ * section_index - Zero-based index of the section to be relocated.
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*relocate_a_section)(void* obj, Dwarf_Half section_index,
+ Dwarf_Debug dbg,
+ int* error);
+
+};
+
+
+
+/* These structures are allocated and deallocated by your code
+ when you are using the libdwarf Object File Interface
+ [dwarf_object_init() and dwarf_object_finish()] directly.
+ dwarf_object_finish() does not free
+ struct Dwarf_Obj_Access_Interface_s or its content.
+ (libdwarf does record a pointer to this struct: you must
+ ensure that pointer remains valid for as long as
+ a libdwarf instance is open (meaning
+ after dwarf_init() and before dwarf_finish()).
+
+ If you are reading Elf objects and libelf use dwarf_init()
+ or dwarf_elf_init() which take care of these details.
+*/
+struct Dwarf_Obj_Access_Interface_s {
+ /* object is a void* as it hides the data the object access routines
+ need (which varies by library in use and object format).
+ */
+ void* object;
+ const Dwarf_Obj_Access_Methods * methods;
+};
+
+/* End libdwarf Object File Interface */
+
+/*
+ Dwarf_dealloc() alloc_type arguments.
+ Argument points to:
+*/
+#define DW_DLA_STRING 0x01 /* char* */
+#define DW_DLA_LOC 0x02 /* Dwarf_Loc */
+#define DW_DLA_LOCDESC 0x03 /* Dwarf_Locdesc */
+#define DW_DLA_ELLIST 0x04 /* Dwarf_Ellist (not used)*/
+#define DW_DLA_BOUNDS 0x05 /* Dwarf_Bounds (not used) */
+#define DW_DLA_BLOCK 0x06 /* Dwarf_Block */
+#define DW_DLA_DEBUG 0x07 /* Dwarf_Debug */
+#define DW_DLA_DIE 0x08 /* Dwarf_Die */
+#define DW_DLA_LINE 0x09 /* Dwarf_Line */
+#define DW_DLA_ATTR 0x0a /* Dwarf_Attribute */
+#define DW_DLA_TYPE 0x0b /* Dwarf_Type (not used) */
+#define DW_DLA_SUBSCR 0x0c /* Dwarf_Subscr (not used) */
+#define DW_DLA_GLOBAL 0x0d /* Dwarf_Global */
+#define DW_DLA_ERROR 0x0e /* Dwarf_Error */
+#define DW_DLA_LIST 0x0f /* a list */
+#define DW_DLA_LINEBUF 0x10 /* Dwarf_Line* (not used) */
+#define DW_DLA_ARANGE 0x11 /* Dwarf_Arange */
+#define DW_DLA_ABBREV 0x12 /* Dwarf_Abbrev */
+#define DW_DLA_FRAME_OP 0x13 /* Dwarf_Frame_Op */
+#define DW_DLA_CIE 0x14 /* Dwarf_Cie */
+#define DW_DLA_FDE 0x15 /* Dwarf_Fde */
+#define DW_DLA_LOC_BLOCK 0x16 /* Dwarf_Loc Block (not used) */
+#define DW_DLA_FRAME_BLOCK 0x17 /* Dwarf_Frame Block (not used) */
+#define DW_DLA_FUNC 0x18 /* Dwarf_Func */
+#define DW_DLA_TYPENAME 0x19 /* Dwarf_Type */
+#define DW_DLA_VAR 0x1a /* Dwarf_Var */
+#define DW_DLA_WEAK 0x1b /* Dwarf_Weak */
+#define DW_DLA_ADDR 0x1c /* Dwarf_Addr sized entries */
+#define DW_DLA_RANGES 0x1d /* Dwarf_Ranges */
+
+/* The augmenter string for CIE */
+#define DW_CIE_AUGMENTER_STRING_V0 "z"
+
+/* dwarf_init() access arguments
+*/
+#define DW_DLC_READ 0 /* read only access */
+#define DW_DLC_WRITE 1 /* write only access */
+#define DW_DLC_RDWR 2 /* read/write access NOT SUPPORTED*/
+
+/* pro_init() access flag modifiers
+ If HAVE_DWARF2_99_EXTENSION is defined at libdwarf build time
+ and DW_DLC_OFFSET_SIZE_64 is passed in pro_init() flags then the DWARF3
+ 64 bit offset extension is used to generate 64 bit offsets.
+*/
+#define DW_DLC_SIZE_64 0x40000000 /* 32-bit address-size target */
+#define DW_DLC_SIZE_32 0x20000000 /* 64-bit address-size target */
+#define DW_DLC_OFFSET_SIZE_64 0x10000000 /* 64-bit offset-size DWARF */
+
+/* dwarf_pro_init() access flag modifiers
+*/
+#define DW_DLC_ISA_MIPS 0x00000000 /* MIPS target */
+#define DW_DLC_ISA_IA64 0x01000000 /* IA64 target */
+#define DW_DLC_STREAM_RELOCATIONS 0x02000000 /* Old style binary relocs */
+
+ /* Usable with assembly output because it is up to the producer to
+ deal with locations in whatever manner the producer code wishes.
+ Possibly emitting text an assembler will recognize. */
+#define DW_DLC_SYMBOLIC_RELOCATIONS 0x04000000
+
+#define DW_DLC_TARGET_BIGENDIAN 0x08000000 /* Big endian target */
+#define DW_DLC_TARGET_LITTLEENDIAN 0x00100000 /* Little endian target */
+
+#if 0
+ /*
+ The libdwarf producer interfaces jumble these two semantics together in
+ confusing ways. We *should* have flags like these...
+ But changing the code means a lot of diffs. So for now,
+ we leave things as they are
+ */
+ #define DW_DLC_SUN_OFFSET32 0x00010000 /* use 32-bit sec offsets */
+ #define DW_DLC_SUN_OFFSET64 0x00020000 /* use 64-bit sec offsets */
+ #define DW_DLC_SUN_POINTER32 0x00040000 /* use 4 for address_size */
+ #define DW_DLC_SUN_POINTER64 0x00080000 /* use 8 for address_size */
+#endif
+
+/* dwarf_pcline() slide arguments
+*/
+#define DW_DLS_BACKWARD -1 /* slide backward to find line */
+#define DW_DLS_NOSLIDE 0 /* match exactly without sliding */
+#define DW_DLS_FORWARD 1 /* slide forward to find line */
+
+/* libdwarf error numbers
+*/
+#define DW_DLE_NE 0 /* no error */
+#define DW_DLE_VMM 1 /* dwarf format/library version mismatch */
+#define DW_DLE_MAP 2 /* memory map failure */
+#define DW_DLE_LEE 3 /* libelf error */
+#define DW_DLE_NDS 4 /* no debug section */
+#define DW_DLE_NLS 5 /* no line section */
+#define DW_DLE_ID 6 /* invalid descriptor for query */
+#define DW_DLE_IOF 7 /* I/O failure */
+#define DW_DLE_MAF 8 /* memory allocation failure */
+#define DW_DLE_IA 9 /* invalid argument */
+#define DW_DLE_MDE 10 /* mangled debugging entry */
+#define DW_DLE_MLE 11 /* mangled line number entry */
+#define DW_DLE_FNO 12 /* file not open */
+#define DW_DLE_FNR 13 /* file not a regular file */
+#define DW_DLE_FWA 14 /* file open with wrong access */
+#define DW_DLE_NOB 15 /* not an object file */
+#define DW_DLE_MOF 16 /* mangled object file header */
+#define DW_DLE_EOLL 17 /* end of location list entries */
+#define DW_DLE_NOLL 18 /* no location list section */
+#define DW_DLE_BADOFF 19 /* Invalid offset */
+#define DW_DLE_EOS 20 /* end of section */
+#define DW_DLE_ATRUNC 21 /* abbreviations section appears truncated*/
+#define DW_DLE_BADBITC 22 /* Address size passed to dwarf bad*/
+ /* It is not an allowed size (64 or 32) */
+ /* Error codes defined by the current Libdwarf Implementation. */
+#define DW_DLE_DBG_ALLOC 23
+#define DW_DLE_FSTAT_ERROR 24
+#define DW_DLE_FSTAT_MODE_ERROR 25
+#define DW_DLE_INIT_ACCESS_WRONG 26
+#define DW_DLE_ELF_BEGIN_ERROR 27
+#define DW_DLE_ELF_GETEHDR_ERROR 28
+#define DW_DLE_ELF_GETSHDR_ERROR 29
+#define DW_DLE_ELF_STRPTR_ERROR 30
+#define DW_DLE_DEBUG_INFO_DUPLICATE 31
+#define DW_DLE_DEBUG_INFO_NULL 32
+#define DW_DLE_DEBUG_ABBREV_DUPLICATE 33
+#define DW_DLE_DEBUG_ABBREV_NULL 34
+#define DW_DLE_DEBUG_ARANGES_DUPLICATE 35
+#define DW_DLE_DEBUG_ARANGES_NULL 36
+#define DW_DLE_DEBUG_LINE_DUPLICATE 37
+#define DW_DLE_DEBUG_LINE_NULL 38
+#define DW_DLE_DEBUG_LOC_DUPLICATE 39
+#define DW_DLE_DEBUG_LOC_NULL 40
+#define DW_DLE_DEBUG_MACINFO_DUPLICATE 41
+#define DW_DLE_DEBUG_MACINFO_NULL 42
+#define DW_DLE_DEBUG_PUBNAMES_DUPLICATE 43
+#define DW_DLE_DEBUG_PUBNAMES_NULL 44
+#define DW_DLE_DEBUG_STR_DUPLICATE 45
+#define DW_DLE_DEBUG_STR_NULL 46
+#define DW_DLE_CU_LENGTH_ERROR 47
+#define DW_DLE_VERSION_STAMP_ERROR 48
+#define DW_DLE_ABBREV_OFFSET_ERROR 49
+#define DW_DLE_ADDRESS_SIZE_ERROR 50
+#define DW_DLE_DEBUG_INFO_PTR_NULL 51
+#define DW_DLE_DIE_NULL 52
+#define DW_DLE_STRING_OFFSET_BAD 53
+#define DW_DLE_DEBUG_LINE_LENGTH_BAD 54
+#define DW_DLE_LINE_PROLOG_LENGTH_BAD 55
+#define DW_DLE_LINE_NUM_OPERANDS_BAD 56
+#define DW_DLE_LINE_SET_ADDR_ERROR 57 /* No longer used. */
+#define DW_DLE_LINE_EXT_OPCODE_BAD 58
+#define DW_DLE_DWARF_LINE_NULL 59
+#define DW_DLE_INCL_DIR_NUM_BAD 60
+#define DW_DLE_LINE_FILE_NUM_BAD 61
+#define DW_DLE_ALLOC_FAIL 62
+#define DW_DLE_NO_CALLBACK_FUNC 63
+#define DW_DLE_SECT_ALLOC 64
+#define DW_DLE_FILE_ENTRY_ALLOC 65
+#define DW_DLE_LINE_ALLOC 66
+#define DW_DLE_FPGM_ALLOC 67
+#define DW_DLE_INCDIR_ALLOC 68
+#define DW_DLE_STRING_ALLOC 69
+#define DW_DLE_CHUNK_ALLOC 70
+#define DW_DLE_BYTEOFF_ERR 71
+#define DW_DLE_CIE_ALLOC 72
+#define DW_DLE_FDE_ALLOC 73
+#define DW_DLE_REGNO_OVFL 74
+#define DW_DLE_CIE_OFFS_ALLOC 75
+#define DW_DLE_WRONG_ADDRESS 76
+#define DW_DLE_EXTRA_NEIGHBORS 77
+#define DW_DLE_WRONG_TAG 78
+#define DW_DLE_DIE_ALLOC 79
+#define DW_DLE_PARENT_EXISTS 80
+#define DW_DLE_DBG_NULL 81
+#define DW_DLE_DEBUGLINE_ERROR 82
+#define DW_DLE_DEBUGFRAME_ERROR 83
+#define DW_DLE_DEBUGINFO_ERROR 84
+#define DW_DLE_ATTR_ALLOC 85
+#define DW_DLE_ABBREV_ALLOC 86
+#define DW_DLE_OFFSET_UFLW 87
+#define DW_DLE_ELF_SECT_ERR 88
+#define DW_DLE_DEBUG_FRAME_LENGTH_BAD 89
+#define DW_DLE_FRAME_VERSION_BAD 90
+#define DW_DLE_CIE_RET_ADDR_REG_ERROR 91
+#define DW_DLE_FDE_NULL 92
+#define DW_DLE_FDE_DBG_NULL 93
+#define DW_DLE_CIE_NULL 94
+#define DW_DLE_CIE_DBG_NULL 95
+#define DW_DLE_FRAME_TABLE_COL_BAD 96
+#define DW_DLE_PC_NOT_IN_FDE_RANGE 97
+#define DW_DLE_CIE_INSTR_EXEC_ERROR 98
+#define DW_DLE_FRAME_INSTR_EXEC_ERROR 99
+#define DW_DLE_FDE_PTR_NULL 100
+#define DW_DLE_RET_OP_LIST_NULL 101
+#define DW_DLE_LINE_CONTEXT_NULL 102
+#define DW_DLE_DBG_NO_CU_CONTEXT 103
+#define DW_DLE_DIE_NO_CU_CONTEXT 104
+#define DW_DLE_FIRST_DIE_NOT_CU 105
+#define DW_DLE_NEXT_DIE_PTR_NULL 106
+#define DW_DLE_DEBUG_FRAME_DUPLICATE 107
+#define DW_DLE_DEBUG_FRAME_NULL 108
+#define DW_DLE_ABBREV_DECODE_ERROR 109
+#define DW_DLE_DWARF_ABBREV_NULL 110
+#define DW_DLE_ATTR_NULL 111
+#define DW_DLE_DIE_BAD 112
+#define DW_DLE_DIE_ABBREV_BAD 113
+#define DW_DLE_ATTR_FORM_BAD 114
+#define DW_DLE_ATTR_NO_CU_CONTEXT 115
+#define DW_DLE_ATTR_FORM_SIZE_BAD 116
+#define DW_DLE_ATTR_DBG_NULL 117
+#define DW_DLE_BAD_REF_FORM 118
+#define DW_DLE_ATTR_FORM_OFFSET_BAD 119
+#define DW_DLE_LINE_OFFSET_BAD 120
+#define DW_DLE_DEBUG_STR_OFFSET_BAD 121
+#define DW_DLE_STRING_PTR_NULL 122
+#define DW_DLE_PUBNAMES_VERSION_ERROR 123
+#define DW_DLE_PUBNAMES_LENGTH_BAD 124
+#define DW_DLE_GLOBAL_NULL 125
+#define DW_DLE_GLOBAL_CONTEXT_NULL 126
+#define DW_DLE_DIR_INDEX_BAD 127
+#define DW_DLE_LOC_EXPR_BAD 128
+#define DW_DLE_DIE_LOC_EXPR_BAD 129
+#define DW_DLE_ADDR_ALLOC 130
+#define DW_DLE_OFFSET_BAD 131
+#define DW_DLE_MAKE_CU_CONTEXT_FAIL 132
+#define DW_DLE_REL_ALLOC 133
+#define DW_DLE_ARANGE_OFFSET_BAD 134
+#define DW_DLE_SEGMENT_SIZE_BAD 135
+#define DW_DLE_ARANGE_LENGTH_BAD 136
+#define DW_DLE_ARANGE_DECODE_ERROR 137
+#define DW_DLE_ARANGES_NULL 138
+#define DW_DLE_ARANGE_NULL 139
+#define DW_DLE_NO_FILE_NAME 140
+#define DW_DLE_NO_COMP_DIR 141
+#define DW_DLE_CU_ADDRESS_SIZE_BAD 142
+#define DW_DLE_INPUT_ATTR_BAD 143
+#define DW_DLE_EXPR_NULL 144
+#define DW_DLE_BAD_EXPR_OPCODE 145
+#define DW_DLE_EXPR_LENGTH_BAD 146
+#define DW_DLE_MULTIPLE_RELOC_IN_EXPR 147
+#define DW_DLE_ELF_GETIDENT_ERROR 148
+#define DW_DLE_NO_AT_MIPS_FDE 149
+#define DW_DLE_NO_CIE_FOR_FDE 150
+#define DW_DLE_DIE_ABBREV_LIST_NULL 151
+#define DW_DLE_DEBUG_FUNCNAMES_DUPLICATE 152
+#define DW_DLE_DEBUG_FUNCNAMES_NULL 153
+#define DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR 154
+#define DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD 155
+#define DW_DLE_FUNC_NULL 156
+#define DW_DLE_FUNC_CONTEXT_NULL 157
+#define DW_DLE_DEBUG_TYPENAMES_DUPLICATE 158
+#define DW_DLE_DEBUG_TYPENAMES_NULL 159
+#define DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR 160
+#define DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD 161
+#define DW_DLE_TYPE_NULL 162
+#define DW_DLE_TYPE_CONTEXT_NULL 163
+#define DW_DLE_DEBUG_VARNAMES_DUPLICATE 164
+#define DW_DLE_DEBUG_VARNAMES_NULL 165
+#define DW_DLE_DEBUG_VARNAMES_VERSION_ERROR 166
+#define DW_DLE_DEBUG_VARNAMES_LENGTH_BAD 167
+#define DW_DLE_VAR_NULL 168
+#define DW_DLE_VAR_CONTEXT_NULL 169
+#define DW_DLE_DEBUG_WEAKNAMES_DUPLICATE 170
+#define DW_DLE_DEBUG_WEAKNAMES_NULL 171
+#define DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR 172
+#define DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD 173
+#define DW_DLE_WEAK_NULL 174
+#define DW_DLE_WEAK_CONTEXT_NULL 175
+#define DW_DLE_LOCDESC_COUNT_WRONG 176
+#define DW_DLE_MACINFO_STRING_NULL 177
+#define DW_DLE_MACINFO_STRING_EMPTY 178
+#define DW_DLE_MACINFO_INTERNAL_ERROR_SPACE 179
+#define DW_DLE_MACINFO_MALLOC_FAIL 180
+#define DW_DLE_DEBUGMACINFO_ERROR 181
+#define DW_DLE_DEBUG_MACRO_LENGTH_BAD 182
+#define DW_DLE_DEBUG_MACRO_MAX_BAD 183
+#define DW_DLE_DEBUG_MACRO_INTERNAL_ERR 184
+#define DW_DLE_DEBUG_MACRO_MALLOC_SPACE 185
+#define DW_DLE_DEBUG_MACRO_INCONSISTENT 186
+#define DW_DLE_DF_NO_CIE_AUGMENTATION 187
+#define DW_DLE_DF_REG_NUM_TOO_HIGH 188
+#define DW_DLE_DF_MAKE_INSTR_NO_INIT 189
+#define DW_DLE_DF_NEW_LOC_LESS_OLD_LOC 190
+#define DW_DLE_DF_POP_EMPTY_STACK 191
+#define DW_DLE_DF_ALLOC_FAIL 192
+#define DW_DLE_DF_FRAME_DECODING_ERROR 193
+#define DW_DLE_DEBUG_LOC_SECTION_SHORT 194
+#define DW_DLE_FRAME_AUGMENTATION_UNKNOWN 195
+#define DW_DLE_PUBTYPE_CONTEXT 196 /* Unused. */
+#define DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD 197
+#define DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR 198
+#define DW_DLE_DEBUG_PUBTYPES_DUPLICATE 199
+#define DW_DLE_FRAME_CIE_DECODE_ERROR 200
+#define DW_DLE_FRAME_REGISTER_UNREPRESENTABLE 201
+#define DW_DLE_FRAME_REGISTER_COUNT_MISMATCH 202
+#define DW_DLE_LINK_LOOP 203
+#define DW_DLE_STRP_OFFSET_BAD 204
+#define DW_DLE_DEBUG_RANGES_DUPLICATE 205
+#define DW_DLE_DEBUG_RANGES_OFFSET_BAD 206
+#define DW_DLE_DEBUG_RANGES_MISSING_END 207
+#define DW_DLE_DEBUG_RANGES_OUT_OF_MEM 208
+#define DW_DLE_DEBUG_SYMTAB_ERR 209
+#define DW_DLE_DEBUG_STRTAB_ERR 210
+#define DW_DLE_RELOC_MISMATCH_INDEX 211
+#define DW_DLE_RELOC_MISMATCH_RELOC_INDEX 212
+#define DW_DLE_RELOC_MISMATCH_STRTAB_INDEX 213
+#define DW_DLE_RELOC_SECTION_MISMATCH 214
+#define DW_DLE_RELOC_SECTION_MISSING_INDEX 215
+#define DW_DLE_RELOC_SECTION_LENGTH_ODD 216
+#define DW_DLE_RELOC_SECTION_PTR_NULL 217
+#define DW_DLE_RELOC_SECTION_MALLOC_FAIL 218
+#define DW_DLE_NO_ELF64_SUPPORT 219
+#define DW_DLE_MISSING_ELF64_SUPPORT 220
+#define DW_DLE_ORPHAN_FDE 221
+#define DW_DLE_DUPLICATE_INST_BLOCK 222
+#define DW_DLE_BAD_REF_SIG8_FORM 223
+#define DW_DLE_ATTR_EXPRLOC_FORM_BAD 224
+#define DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD 225
+#define DW_DLE_NOT_REF_FORM 226
+#define DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE 227
+
+
+
+ /* DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */
+#define DW_DLE_LAST 227
+#define DW_DLE_LO_USER 0x10000
+
+ /* Taken as meaning 'undefined value', this is not
+ a column or register number.
+ Only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ */
+#define DW_FRAME_UNDEFINED_VAL 1034
+
+ /* Taken as meaning 'same value' as caller had, not a column
+ or register number
+ Only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ */
+#define DW_FRAME_SAME_VAL 1035
+
+
+
+/* error return values
+*/
+#define DW_DLV_BADADDR (~(Dwarf_Addr)0)
+ /* for functions returning target address */
+
+#define DW_DLV_NOCOUNT ((Dwarf_Signed)-1)
+ /* for functions returning count */
+
+#define DW_DLV_BADOFFSET (~(Dwarf_Off)0)
+ /* for functions returning offset */
+
+/* standard return values for functions */
+#define DW_DLV_NO_ENTRY -1
+#define DW_DLV_OK 0
+#define DW_DLV_ERROR 1
+
+/* Special values for offset_into_exception_table field of dwarf fde's. */
+/* The following value indicates that there is no Exception table offset
+ associated with a dwarf frame. */
+#define DW_DLX_NO_EH_OFFSET (-1LL)
+/* The following value indicates that the producer was unable to analyse the
+ source file to generate Exception tables for this function. */
+#define DW_DLX_EH_OFFSET_UNAVAILABLE (-2LL)
+
+
+/*===========================================================================*/
+/* Dwarf consumer interface initialization and termination operations */
+
+/* Initialization based on Unix open fd (using libelf internally). */
+int dwarf_init(int /*fd*/,
+ Dwarf_Unsigned /*access*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Debug* /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Initialization based on libelf/sgi-fastlibelf open pointer. */
+int dwarf_elf_init(dwarf_elf_handle /*elf*/,
+ Dwarf_Unsigned /*access*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Debug* /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Undocumented function for memory allocator. */
+void dwarf_print_memory_stats(Dwarf_Debug /*dbg*/);
+
+int dwarf_get_elf(Dwarf_Debug /*dbg*/,
+ dwarf_elf_handle* /*return_elfptr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_finish(Dwarf_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+
+int dwarf_object_init(Dwarf_Obj_Access_Interface* /* obj */,
+ Dwarf_Handler /* errhand */,
+ Dwarf_Ptr /* errarg */,
+ Dwarf_Debug* /* dbg */,
+ Dwarf_Error* /* error */);
+
+int dwarf_object_finish(Dwarf_Debug /* dbg */,
+ Dwarf_Error* /* error */);
+
+/* die traversal operations */
+int dwarf_next_cu_header_b(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned* /*cu_header_length*/,
+ Dwarf_Half* /*version_stamp*/,
+ Dwarf_Off* /*abbrev_offset*/,
+ Dwarf_Half* /*address_size*/,
+ Dwarf_Half* /*length_size*/,
+ Dwarf_Half* /*extension_size*/,
+ Dwarf_Unsigned* /*next_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+/* The following is now obsolete, though supported. November 2009. */
+int dwarf_next_cu_header(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned* /*cu_header_length*/,
+ Dwarf_Half* /*version_stamp*/,
+ Dwarf_Off* /*abbrev_offset*/,
+ Dwarf_Half* /*address_size*/,
+ Dwarf_Unsigned* /*next_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_siblingof(Dwarf_Debug /*dbg*/,
+ Dwarf_Die /*die*/,
+ Dwarf_Die* /*return_siblingdie*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_child(Dwarf_Die /*die*/,
+ Dwarf_Die* /*return_childdie*/,
+ Dwarf_Error* /*error*/);
+
+/* Finding die given global (not CU-relative) offset */
+int dwarf_offdie(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*offset*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Higher level functions (Unimplemented) */
+int dwarf_pcfile(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_pcsubr(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_pcscope(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* operations on DIEs */
+int dwarf_tag(Dwarf_Die /*die*/,
+ Dwarf_Half* /*return_tag*/,
+ Dwarf_Error* /*error*/);
+
+/* utility? */
+/* dwarf_dieoffset returns the global debug_info
+ section offset, not the CU relative offset. */
+int dwarf_dieoffset(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_CU_dieoffset_given_die returns
+ the global debug_info section offset of the CU die
+ that is the CU containing the given_die
+ (the passed in DIE can be any DIE).
+ This information makes it possible for a consumer to
+ find and print CU context information for any die.
+ See also dwarf_get_cu_die_offset_given_cu_header_offset(). */
+int dwarf_CU_dieoffset_given_die(Dwarf_Die /*given_die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_die_CU_offset returns the CU relative offset
+ not the global debug_info section offset, given
+ any DIE in the CU. See also dwarf_CU_dieoffset_given_die().
+ */
+int dwarf_die_CU_offset(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_die_CU_offset_range(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_CU_header_offset*/,
+ Dwarf_Off* /*return_CU_length_bytes*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_attr (Dwarf_Die /*die*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Attribute * /*returned_attr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_diename(Dwarf_Die /*die*/,
+ char ** /*diename*/,
+ Dwarf_Error* /*error*/);
+
+/* Returns the abbrev code of the die. Cannot fail. */
+int dwarf_die_abbrev_code(Dwarf_Die /*die */);
+
+
+/* convenience functions, alternative to using dwarf_attrlist() */
+int dwarf_hasattr(Dwarf_Die /*die*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_loclist_n preferred over dwarf_loclist */
+int dwarf_loclist_n(Dwarf_Attribute /*attr*/,
+ Dwarf_Locdesc*** /*llbuf*/,
+ Dwarf_Signed * /*locCount*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_loclist(Dwarf_Attribute /*attr*/, /* inflexible! */
+ Dwarf_Locdesc** /*llbuf*/,
+ Dwarf_Signed * /*locCount*/,
+ Dwarf_Error* /*error*/);
+
+/* Extracts a dwarf expression from an expression byte stream.
+ Useful to get expressions from DW_CFA_def_cfa_expression
+ DW_CFA_expression DW_CFA_val_expression expression bytes.
+ 27 April 2009: dwarf_loclist_from_expr() interface with
+ no addr_size is obsolete but supported,
+ use dwarf_loclist_from_expr_a() instead.
+*/
+int dwarf_loclist_from_expr(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error);
+
+/* dwarf_loclist_from_expr_a() new 27 Apr 2009: added addr_size argument. */
+int dwarf_loclist_from_expr_a(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Half addr_size,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error);
+
+/* Unimplemented */
+int dwarf_stringlen(Dwarf_Die /*die*/,
+ Dwarf_Locdesc ** /*returned_locdesc*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_subscrcnt(Dwarf_Die /*die*/,
+ Dwarf_Signed * /*returned_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_nthsubscr(Dwarf_Die /*die*/,
+ Dwarf_Unsigned /*ssndx*/,
+ Dwarf_Die * /*returned_die*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lowpc(Dwarf_Die /*die*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_highpc(Dwarf_Die /*die*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bytesize(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_size*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_isbitfield(Dwarf_Die /*die*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bitsize(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_size*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bitoffset(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_srclang(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_lang*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_arrayorder(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_order*/,
+ Dwarf_Error* /*error*/);
+
+/* end of convenience function list */
+
+/* this is the main interface to attributes of a DIE */
+int dwarf_attrlist(Dwarf_Die /*die*/,
+ Dwarf_Attribute** /*attrbuf*/,
+ Dwarf_Signed * /*attrcount*/,
+ Dwarf_Error* /*error*/);
+
+/* query operations for attributes */
+int dwarf_hasform(Dwarf_Attribute /*attr*/,
+ Dwarf_Half /*form*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatform(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_form*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatform_direct(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_form*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatattr(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_attr_num*/,
+ Dwarf_Error* /*error*/);
+
+/*
+ The following are concerned with the Primary Interface: getting
+ the actual data values. One function per 'kind' of FORM.
+*/
+/* dwarf_formref returns, thru return_offset, a CU-relative offset
+ and does not allow DW_FORM_ref_addr*/
+int dwarf_formref(Dwarf_Attribute /*attr*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+/* dwarf_global_formref returns, thru return_offset,
+ a debug_info-relative offset and does allow all reference forms*/
+int dwarf_global_formref(Dwarf_Attribute /*attr*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_formsig8 returns in the caller-provided 8 byte area
+ the 8 bytes of a DW_FORM_ref_sig8. Not a string. */
+int dwarf_formsig8(Dwarf_Attribute /*attr*/,
+ Dwarf_Sig8 * /*returned sig bytes*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formaddr(Dwarf_Attribute /*attr*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formflag(Dwarf_Attribute /*attr*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formudata(Dwarf_Attribute /*attr*/,
+ Dwarf_Unsigned * /*returned_val*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formsdata(Dwarf_Attribute /*attr*/,
+ Dwarf_Signed * /*returned_val*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formblock(Dwarf_Attribute /*attr*/,
+ Dwarf_Block ** /*returned_block*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formstring(Dwarf_Attribute /*attr*/,
+ char ** /*returned_string*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formexprloc(Dwarf_Attribute /*attr*/,
+ Dwarf_Unsigned * /*return_exprlen*/,
+ Dwarf_Ptr * /*block_ptr*/,
+ Dwarf_Error * /*error*/);
+
+
+/* end attribute query operations. */
+
+/* line number operations */
+/* dwarf_srclines is the normal interface */
+int dwarf_srclines(Dwarf_Die /*die*/,
+ Dwarf_Line** /*linebuf*/,
+ Dwarf_Signed * /*linecount*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_srclines_dealloc, created July 2005, is the new
+ method for deallocating what dwarf_srclines returns.
+ More complete free than using dwarf_dealloc directly. */
+void dwarf_srclines_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Line* /*linebuf*/,
+ Dwarf_Signed /*count */);
+
+
+int dwarf_srcfiles(Dwarf_Die /*die*/,
+ char*** /*srcfiles*/,
+ Dwarf_Signed * /*filecount*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented. */
+int dwarf_dieline(Dwarf_Die /*die*/,
+ Dwarf_Line * /*returned_line*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_linebeginstatement(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineendsequence(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineno(Dwarf_Line /*line*/,
+ Dwarf_Unsigned * /*returned_lineno*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_line_srcfileno(Dwarf_Line /*line*/,
+ Dwarf_Unsigned * /*ret_fileno*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_lineaddr(Dwarf_Line /*line*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineoff(Dwarf_Line /*line*/,
+ Dwarf_Signed * /*returned_lineoffset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_linesrc(Dwarf_Line /*line*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineblock(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+/* tertiary interface to line info */
+/* Unimplemented */
+int dwarf_pclines(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Line** /*linebuf*/,
+ Dwarf_Signed * /*linecount*/,
+ Dwarf_Signed /*slide*/,
+ Dwarf_Error* /*error*/);
+/* end line number operations */
+
+/* global name space operations (.debug_pubnames access) */
+int dwarf_get_globals(Dwarf_Debug /*dbg*/,
+ Dwarf_Global** /*globals*/,
+ Dwarf_Signed * /*number_of_globals*/,
+ Dwarf_Error* /*error*/);
+void dwarf_globals_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Global* /*globals*/,
+ Dwarf_Signed /*number_of_globals*/);
+
+int dwarf_globname(Dwarf_Global /*glob*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_global_die_offset(Dwarf_Global /*global*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error * /*error*/);
+
+/* This returns the CU die global offset if one knows the
+ CU header global offset.
+ See also dwarf_CU_dieoffset_given_die(). */
+int dwarf_get_cu_die_offset_given_cu_header_offset(
+ Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*in_cu_header_offset*/,
+ Dwarf_Off * /*out_cu_die_offset*/,
+ Dwarf_Error * /*err*/);
+#ifdef __sgi /* pragma is sgi MIPS only */
+#pragma optional dwarf_get_cu_die_offset_given_cu_header_offset
+#endif
+
+int dwarf_global_cu_offset(Dwarf_Global /*global*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_global_name_offsets(Dwarf_Global /*global*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* Static function name operations. */
+int dwarf_get_funcs(Dwarf_Debug /*dbg*/,
+ Dwarf_Func** /*funcs*/,
+ Dwarf_Signed * /*number_of_funcs*/,
+ Dwarf_Error* /*error*/);
+void dwarf_funcs_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Func* /*funcs*/,
+ Dwarf_Signed /*number_of_funcs*/);
+
+int dwarf_funcname(Dwarf_Func /*func*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_die_offset(Dwarf_Func /*func*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_cu_offset(Dwarf_Func /*func*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_name_offsets(Dwarf_Func /*func*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* User-defined type name operations, SGI IRIX .debug_typenames section.
+ Same content as DWARF3 .debug_pubtypes, but defined years before
+ .debug_pubtypes was defined. SGI IRIX only. */
+int dwarf_get_types(Dwarf_Debug /*dbg*/,
+ Dwarf_Type** /*types*/,
+ Dwarf_Signed * /*number_of_types*/,
+ Dwarf_Error* /*error*/);
+void dwarf_types_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Type* /*types*/,
+ Dwarf_Signed /*number_of_types*/);
+
+
+int dwarf_typename(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_die_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_cu_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_name_offsets(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* User-defined type name operations, DWARF3 .debug_pubtypes section.
+*/
+int dwarf_get_pubtypes(Dwarf_Debug /*dbg*/,
+ Dwarf_Type** /*types*/,
+ Dwarf_Signed * /*number_of_types*/,
+ Dwarf_Error* /*error*/);
+void dwarf_pubtypes_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Type* /*pubtypes*/,
+ Dwarf_Signed /*number_of_pubtypes*/);
+
+
+int dwarf_pubtypename(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_die_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_cu_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_name_offsets(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* File-scope static variable name operations. */
+int dwarf_get_vars(Dwarf_Debug /*dbg*/,
+ Dwarf_Var** /*vars*/,
+ Dwarf_Signed * /*number_of_vars*/,
+ Dwarf_Error* /*error*/);
+void dwarf_vars_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Var* /*vars*/,
+ Dwarf_Signed /*number_of_vars*/);
+
+
+int dwarf_varname(Dwarf_Var /*var*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_die_offset(Dwarf_Var /*var*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_cu_offset(Dwarf_Var /*var*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_name_offsets(Dwarf_Var /*var*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* weak name operations. */
+int dwarf_get_weaks(Dwarf_Debug /*dbg*/,
+ Dwarf_Weak** /*weaks*/,
+ Dwarf_Signed * /*number_of_weaks*/,
+ Dwarf_Error* /*error*/);
+void dwarf_weaks_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Weak* /*weaks*/,
+ Dwarf_Signed /*number_of_weaks*/);
+
+
+int dwarf_weakname(Dwarf_Weak /*weak*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_die_offset(Dwarf_Weak /*weak*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_cu_offset(Dwarf_Weak /*weak*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_name_offsets(Dwarf_Weak /*weak*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* location list section operation. (.debug_loc access) */
+int dwarf_get_loclist_entry(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Addr* /*hipc*/,
+ Dwarf_Addr* /*lopc*/,
+ Dwarf_Ptr* /*data*/,
+ Dwarf_Unsigned* /*entry_len*/,
+ Dwarf_Unsigned* /*next_entry*/,
+ Dwarf_Error* /*error*/);
+
+/* abbreviation section operations */
+int dwarf_get_abbrev(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Abbrev * /*returned_abbrev*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Unsigned* /*attr_count*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_tag(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Half* /*return_tag_number*/,
+ Dwarf_Error* /*error*/);
+int dwarf_get_abbrev_code(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Unsigned* /*return_code_number*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_children_flag(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Signed* /*return_flag*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_entry(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Signed /*index*/,
+ Dwarf_Half * /*returned_attr_num*/,
+ Dwarf_Signed* /*form*/,
+ Dwarf_Off* /*offset*/,
+ Dwarf_Error* /*error*/);
+
+/* consumer string section operation */
+int dwarf_get_str(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*offset*/,
+ char** /*string*/,
+ Dwarf_Signed * /*strlen_of_string*/,
+ Dwarf_Error* /*error*/);
+
+/* Consumer op on gnu .eh_frame info */
+int dwarf_get_fde_list_eh(
+ Dwarf_Debug /*dbg*/,
+ Dwarf_Cie** /*cie_data*/,
+ Dwarf_Signed* /*cie_element_count*/,
+ Dwarf_Fde** /*fde_data*/,
+ Dwarf_Signed* /*fde_element_count*/,
+ Dwarf_Error* /*error*/);
+
+
+/* consumer operations on frame info: .debug_frame */
+int dwarf_get_fde_list(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie** /*cie_data*/,
+ Dwarf_Signed* /*cie_element_count*/,
+ Dwarf_Fde** /*fde_data*/,
+ Dwarf_Signed* /*fde_element_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Release storage gotten by dwarf_get_fde_list_eh() or
+ dwarf_get_fde_list() */
+void dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
+ Dwarf_Cie *cie_data,
+ Dwarf_Signed cie_element_count,
+ Dwarf_Fde *fde_data,
+ Dwarf_Signed fde_element_count);
+
+
+
+int dwarf_get_fde_range(Dwarf_Fde /*fde*/,
+ Dwarf_Addr* /*low_pc*/,
+ Dwarf_Unsigned* /*func_length*/,
+ Dwarf_Ptr* /*fde_bytes*/,
+ Dwarf_Unsigned* /*fde_byte_length*/,
+ Dwarf_Off* /*cie_offset*/,
+ Dwarf_Signed* /*cie_index*/,
+ Dwarf_Off* /*fde_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* Useful for IRIX only: see dwarf_get_cie_augmentation_data()
+ dwarf_get_fde_augmentation_data() for GNU .eh_frame. */
+int dwarf_get_fde_exception_info(Dwarf_Fde /*fde*/,
+ Dwarf_Signed* /* offset_into_exception_tables */,
+ Dwarf_Error* /*error*/);
+
+
+int dwarf_get_cie_of_fde(Dwarf_Fde /*fde*/,
+ Dwarf_Cie * /*cie_returned*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_cie_info(Dwarf_Cie /*cie*/,
+ Dwarf_Unsigned * /*bytes_in_cie*/,
+ Dwarf_Small* /*version*/,
+ char ** /*augmenter*/,
+ Dwarf_Unsigned* /*code_alignment_factor*/,
+ Dwarf_Signed* /*data_alignment_factor*/,
+ Dwarf_Half* /*return_address_register_rule*/,
+ Dwarf_Ptr* /*initial_instructions*/,
+ Dwarf_Unsigned* /*initial_instructions_length*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_get_cie_index new September 2009. */
+int dwarf_get_cie_index(
+ Dwarf_Cie /*cie*/,
+ Dwarf_Signed* /*index*/,
+ Dwarf_Error* /*error*/ );
+
+
+int dwarf_get_fde_instr_bytes(Dwarf_Fde /*fde*/,
+ Dwarf_Ptr * /*outinstrs*/, Dwarf_Unsigned * /*outlen*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_fde_info_for_all_regs(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Regtable* /*reg_table*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Regtable3* /*reg_table*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+/* In this older interface DW_FRAME_CFA_COL is a meaningful
+ column (which does not work well with DWARF3 or
+ non-MIPS architectures). */
+int dwarf_get_fde_info_for_reg(Dwarf_Fde /*fde*/,
+ Dwarf_Half /*table_column*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Signed* /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+/* See discussion of dw_value_type, libdwarf.h.
+ Use of DW_FRAME_CFA_COL is not meaningful in this interface.
+ See dwarf_get_fde_info_for_cfa_reg3().
+*/
+/* dwarf_get_fde_info_for_reg3 is useful on a single column, but
+ it is inefficient to iterate across all table_columns using this
+ function. Instead call dwarf_get_fde_info_for_all_regs3() and index
+ into the table it fills in. */
+int dwarf_get_fde_info_for_reg3(Dwarf_Fde /*fde*/,
+ Dwarf_Half /*table_column*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Small * /*value_type*/,
+ Dwarf_Signed * /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset_or_block_len*/,
+ Dwarf_Ptr * /*block_ptr */,
+ Dwarf_Addr* /*row_pc_out*/,
+ Dwarf_Error* /*error*/);
+
+/* Use this to get the cfa. */
+int dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Small * /*value_type*/,
+ Dwarf_Signed * /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset_or_block_len*/,
+ Dwarf_Ptr * /*block_ptr */,
+ Dwarf_Addr* /*row_pc_out*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_for_die(Dwarf_Debug /*dbg*/,
+ Dwarf_Die /*subr_die */,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_n(Dwarf_Fde* /*fde_data*/,
+ Dwarf_Unsigned /*fde_index*/,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_at_pc(Dwarf_Fde* /*fde_data*/,
+ Dwarf_Addr /*pc_of_interest*/,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Addr* /*lopc*/,
+ Dwarf_Addr* /*hipc*/,
+ Dwarf_Error* /*error*/);
+
+/* GNU .eh_frame augmentation information, raw form, see
+ Linux Standard Base Core Specification version 3.0 . */
+int dwarf_get_cie_augmentation_data(Dwarf_Cie /* cie*/,
+ Dwarf_Small ** /* augdata */,
+ Dwarf_Unsigned * /* augdata_len */,
+ Dwarf_Error* /*error*/);
+/* GNU .eh_frame augmentation information, raw form, see
+ Linux Standard Base Core Specification version 3.0 . */
+int dwarf_get_fde_augmentation_data(Dwarf_Fde /* fde*/,
+ Dwarf_Small ** /* augdata */,
+ Dwarf_Unsigned * /* augdata_len */,
+ Dwarf_Error* /*error*/);
+
+int dwarf_expand_frame_instructions(Dwarf_Cie /*cie*/,
+ Dwarf_Ptr /*instruction*/,
+ Dwarf_Unsigned /*i_length*/,
+ Dwarf_Frame_Op** /*returned_op_list*/,
+ Dwarf_Signed* /*op_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Operations on .debug_aranges. */
+int dwarf_get_aranges(Dwarf_Debug /*dbg*/,
+ Dwarf_Arange** /*aranges*/,
+ Dwarf_Signed * /*arange_count*/,
+ Dwarf_Error* /*error*/);
+
+
+
+int dwarf_get_arange(
+ Dwarf_Arange* /*aranges*/,
+ Dwarf_Unsigned /*arange_count*/,
+ Dwarf_Addr /*address*/,
+ Dwarf_Arange * /*returned_arange*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_cu_die_offset(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_arange_cu_header_offset(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Off* /*return_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+#ifdef __sgi /* pragma is sgi MIPS only */
+#pragma optional dwarf_get_arange_cu_header_offset
+#endif
+
+/* DWARF2,3 interface. No longer really adequate (it was never
+ right for segmented address spaces, please switch
+ to using dwarf_get_arange_info_b instead.
+ There is no effective difference between these
+ functions if the address space
+ of the target is not segmented. */
+int dwarf_get_arange_info(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Addr* /*start*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Off* /*cu_die_offset*/,
+ Dwarf_Error* /*error*/ );
+
+/* New for DWARF4, entries may have segment information.
+ *segment is only meaningful if *segment_entry_size is non-zero. */
+int dwarf_get_arange_info_b(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Unsigned* /*segment*/,
+ Dwarf_Unsigned* /*segment_entry_size*/,
+ Dwarf_Addr * /*start*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Off * /*cu_die_offset*/,
+ Dwarf_Error * /*error*/ );
+
+
+/* consumer .debug_macinfo information interface.
+*/
+struct Dwarf_Macro_Details_s {
+ Dwarf_Off dmd_offset; /* offset, in the section,
+ of this macro info */
+ Dwarf_Small dmd_type; /* the type, DW_MACINFO_define etc*/
+ Dwarf_Signed dmd_lineno; /* the source line number where
+ applicable and vend_def # if
+ vendor_extension op
+ */
+
+ Dwarf_Signed dmd_fileindex;/* the source file index:
+ applies to define undef start_file
+ */
+ char * dmd_macro; /* macro name (with value for defineop)
+ string from vendor ext
+ */
+};
+
+/* dwarf_print_lines is for use by dwarfdump: it prints
+ line info to stdout.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+ Added extra argnument 2/2009 for better checking.
+*/
+int _dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/);
+int dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/,
+ int * /*error_count_out */);
+
+/* dwarf_check_lineheader lets dwarfdump get detailed messages
+ about some compiler errors we detect.
+ We return the count of detected errors throught the
+ pointer.
+*/
+void dwarf_check_lineheader(Dwarf_Die /*cu_die*/,int *errcount_out);
+
+/* dwarf_ld_sort_lines helps SGI IRIX ld
+ rearrange lines in .debug_line in a .o created with a text
+ section per function.
+ -OPT:procedure_reorder=ON
+ where ld-cord (cord(1)ing by ld,
+ not by cord(1)) may have changed the function order.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int _dwarf_ld_sort_lines(
+ void * /*orig_buffer*/,
+ unsigned long /* buffer_len*/,
+ int /*is_64_bit*/,
+ int * /*any_change*/,
+ int * /*err_code*/);
+int dwarf_ld_sort_lines(
+ void * /*orig_buffer*/,
+ unsigned long /*buffer_len*/,
+ int /*is_64_bit*/,
+ int * /*any_change*/,
+ int * /*err_code*/);
+
+/* Used by dwarfdump -v to print fde offsets from debugging
+ info.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int _dwarf_fde_section_offset(Dwarf_Debug dbg,
+ Dwarf_Fde /*in_fde*/,
+ Dwarf_Off * /*fde_off*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+int dwarf_fde_section_offset(Dwarf_Debug dbg,
+ Dwarf_Fde /*in_fde*/,
+ Dwarf_Off * /*fde_off*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+
+/* Used by dwarfdump -v to print cie offsets from debugging
+ info.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int dwarf_cie_section_offset(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie /*in_cie*/,
+ Dwarf_Off * /*cie_off */,
+ Dwarf_Error * /*err*/);
+int _dwarf_cie_section_offset(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie /*in_cie*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+
+typedef struct Dwarf_Macro_Details_s Dwarf_Macro_Details;
+
+int dwarf_get_macro(Dwarf_Debug /*dbg*/,
+ char * /*requested_macro_name*/,
+ Dwarf_Addr /*pc_of_request*/,
+ char ** /*returned_macro_value*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_all_defined_macros(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc_of_request*/,
+ Dwarf_Signed * /*returned_count*/,
+ char *** /*returned_pointers_to_macros*/,
+ Dwarf_Error * /*error*/);
+
+char *dwarf_find_macro_value_start(char * /*macro_string*/);
+
+int dwarf_get_macro_details(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*macro_offset*/,
+ Dwarf_Unsigned /*maximum_count*/,
+ Dwarf_Signed * /*entry_count*/,
+ Dwarf_Macro_Details ** /*details*/,
+ Dwarf_Error * /*err*/);
+
+
+int dwarf_get_address_size(Dwarf_Debug /*dbg*/,
+ Dwarf_Half * /*addr_size*/,
+ Dwarf_Error * /*error*/);
+int dwarf_get_die_address_size(Dwarf_Die /*die*/,
+ Dwarf_Half * /*addr_size*/,
+ Dwarf_Error * /*error*/);
+
+/* The dwarf specification separates FORMs into
+different classes. To do the seperation properly
+requires 4 pieces of data as of DWARF4 (thus the
+function arguments listed here).
+The DWARF4 specification class definition suffices to
+describe all DWARF versions.
+See section 7.5.4, Attribute Encodings.
+A return of DW_FORM_CLASS_UNKNOWN means we could not properly figure
+out what form-class it is.
+
+ DW_FORM_CLASS_FRAMEPTR is MIPS/IRIX only, and refers
+ to the DW_AT_MIPS_fde attribute (a reference to the
+ .debug_frame section).
+*/
+enum Dwarf_Form_Class {
+ DW_FORM_CLASS_UNKNOWN, DW_FORM_CLASS_ADDRESS,
+ DW_FORM_CLASS_BLOCK, DW_FORM_CLASS_CONSTANT,
+ DW_FORM_CLASS_EXPRLOC, DW_FORM_CLASS_FLAG,
+ DW_FORM_CLASS_LINEPTR, DW_FORM_CLASS_LOCLISTPTR,
+ DW_FORM_CLASS_MACPTR, DW_FORM_CLASS_RANGELISTPTR,
+ DW_FORM_CLASS_REFERENCE, DW_FORM_CLASS_STRING,
+ DW_FORM_CLASS_FRAMEPTR
+};
+
+enum Dwarf_Form_Class dwarf_get_form_class(
+ Dwarf_Half /* dwversion */,
+ Dwarf_Half /* attrnum */,
+ Dwarf_Half /*offset_size */,
+ Dwarf_Half /*form*/);
+
+/* utility operations */
+Dwarf_Unsigned dwarf_errno(Dwarf_Error /*error*/);
+
+char* dwarf_errmsg(Dwarf_Error /*error*/);
+
+/* stringcheck zero is default and means do all
+** string length validity checks.
+** Call with parameter value 1 to turn off many such checks (and
+** increase performance).
+** Call with zero for safest running.
+** Actual value saved and returned is only 8 bits! Upper bits
+** ignored by libdwarf (and zero on return).
+** Returns previous value.
+*/
+int dwarf_set_stringcheck(int /*stringcheck*/);
+
+/* 'apply' defaults to 1 and means do all
+ * 'rela' relocations on reading in a dwarf object section with
+ * such relocations.
+ * Call with parameter value 0 to turn off application of
+ * such relocations.
+ * Since the static linker leaves 'bogus' data in object sections
+ * with a 'rela' relocation section such data cannot be read
+ * sensibly without processing the relocations. Such relocations
+ * do not exist in executables and shared objects (.so), the
+ * relocations only exist in plain .o relocatable object files.
+ * Actual value saved and returned is only 8 bits! Upper bits
+ * ignored by libdwarf (and zero on return).
+ * Returns previous value.
+ * */
+int dwarf_set_reloc_application(int /*apply*/);
+
+
+/* Unimplemented */
+Dwarf_Handler dwarf_seterrhand(Dwarf_Debug /*dbg*/, Dwarf_Handler /*errhand*/);
+
+/* Unimplemented */
+Dwarf_Ptr dwarf_seterrarg(Dwarf_Debug /*dbg*/, Dwarf_Ptr /*errarg*/);
+
+void dwarf_dealloc(Dwarf_Debug /*dbg*/, void* /*space*/,
+ Dwarf_Unsigned /*type*/);
+
+/* DWARF Producer Interface */
+
+typedef int (*Dwarf_Callback_Func)(
+ char* /*name*/,
+ int /*size*/,
+ Dwarf_Unsigned /*type*/,
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Unsigned /*link*/,
+ Dwarf_Unsigned /*info*/,
+ int* /*sect name index*/,
+ int* /*error*/);
+
+Dwarf_P_Debug dwarf_producer_init(
+ Dwarf_Unsigned /*creation_flags*/,
+ Dwarf_Callback_Func /*func*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Error* /*error*/);
+
+typedef int (*Dwarf_Callback_Func_b)(
+ char* /*name*/,
+ int /*size*/,
+ Dwarf_Unsigned /*type*/,
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Unsigned /*link*/,
+ Dwarf_Unsigned /*info*/,
+ Dwarf_Unsigned* /*sect_name_index*/,
+ int* /*error*/);
+
+
+Dwarf_P_Debug dwarf_producer_init_b(
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Callback_Func_b /*func*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Error * /*error*/);
+
+
+Dwarf_Signed dwarf_transform_to_disk_form(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Signed /*dwarf_section*/,
+ Dwarf_Signed* /*elf_section_index*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_relocation_info_count(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned * /*count_of_relocation_sections*/,
+ int * /*drd_buffer_version*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_relocation_info(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Signed * /*elf_section_index*/,
+ Dwarf_Signed * /*elf_section_index_link*/,
+ Dwarf_Unsigned * /*relocation_buffer_count*/,
+ Dwarf_Relocation_Data * /*reldata_buffer*/,
+ Dwarf_Error* /*error*/);
+
+/* v1: no drd_length field, enum explicit */
+/* v2: has the drd_length field, enum value in uchar member */
+#define DWARF_DRD_BUFFER_VERSION 2
+
+/* Markers are not written to DWARF2/3/4, they are user
+ defined and may be used for any purpose.
+*/
+Dwarf_Signed dwarf_get_die_markers(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Marker * /*marker_list*/,
+ Dwarf_Unsigned * /*marker_count*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_string_attributes_count(Dwarf_P_Debug,
+ Dwarf_Unsigned *,
+ int *,
+ Dwarf_Error *);
+
+int dwarf_get_string_attributes_info(Dwarf_P_Debug,
+ Dwarf_Signed *,
+ Dwarf_Unsigned *,
+ Dwarf_P_String_Attr *,
+ Dwarf_Error *);
+
+void dwarf_reset_section_bytes(Dwarf_P_Debug /*dbg*/);
+
+Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer attribute addition functions. */
+Dwarf_P_Attribute dwarf_add_AT_targ_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Signed /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_block(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Small* /*block_data*/,
+ Dwarf_Unsigned /*block_len*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_ref_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_unsigned_const(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_signed_const(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Signed /*value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_P_Die /*otherdie*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_dataref(
+ Dwarf_P_Debug /* dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pcvalue*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_string(Dwarf_P_Die /*ownerdie*/,
+ char* /*string_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_P_Expr /*loc_expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_string(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ char* /*string*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_flag(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Small /*flag*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_producer(Dwarf_P_Die /*ownerdie*/,
+ char* /*producer_string*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_signedint(Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Signed /*signed_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_unsignedint(
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Unsigned /*unsigned_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_comp_dir(Dwarf_P_Die /*ownerdie*/,
+ char* /*current_working_directory*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die /*die*/,
+ char* /*name*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer line creation functions (.debug_line) */
+Dwarf_Unsigned dwarf_add_directory_decl(Dwarf_P_Debug /*dbg*/,
+ char* /*name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug /*dbg*/,
+ char* /*name*/,
+ Dwarf_Unsigned /*dir_index*/,
+ Dwarf_Unsigned /*time_last_modified*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_line_entry(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*file_index*/,
+ Dwarf_Addr /*code_address*/,
+ Dwarf_Unsigned /*lineno*/,
+ Dwarf_Signed /*column_number*/,
+ Dwarf_Bool /*is_source_stmt_begin*/,
+ Dwarf_Bool /*is_basic_block_begin*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*end_address*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer .debug_frame functions */
+Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug /*dbg*/,
+ char* /*augmenter*/,
+ Dwarf_Small /*code_alignent_factor*/,
+ Dwarf_Small /*data_alignment_factor*/,
+ Dwarf_Small /*return_address_reg*/,
+ Dwarf_Ptr /*initialization_bytes*/,
+ Dwarf_Unsigned /*init_byte_len*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_fde(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*corresponding subprogram die*/,
+ Dwarf_Unsigned /*cie_to_use*/,
+ Dwarf_Unsigned /*virt_addr_of_described_code*/,
+ Dwarf_Unsigned /*length_of_code*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_fde_b(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*sym_idx*/,
+ Dwarf_Unsigned /*sym_idx_of_end*/,
+ Dwarf_Addr /*offset_from_end_sym*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_info_b(
+ Dwarf_P_Debug dbg /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*symidx*/,
+ Dwarf_Unsigned /*end_symbol */,
+ Dwarf_Addr /*offset_from_end_symbol */,
+ Dwarf_Signed /*offset_into_exception_tables*/,
+ Dwarf_Unsigned /*exception_table_symbol*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_info(
+ Dwarf_P_Debug dbg /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*symidx*/,
+ Dwarf_Signed /*offset_into_exception_tables*/,
+ Dwarf_Unsigned /*exception_table_symbol*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Fde dwarf_add_fde_inst(
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Small /*op*/,
+ Dwarf_Unsigned /*val1*/,
+ Dwarf_Unsigned /*val2*/,
+ Dwarf_Error* /*error*/);
+
+/* New September 17, 2009 */
+int dwarf_insert_fde_inst_bytes(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Unsigned /*len*/,
+ Dwarf_Ptr /*ibytes*/,
+ Dwarf_Error* /*error*/);
+
+
+Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+Dwarf_P_Fde dwarf_fde_cfa_offset(
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Unsigned /*register_number*/,
+ Dwarf_Signed /*offset*/,
+ Dwarf_Error* /*error*/);
+
+/* die creation & addition routines */
+Dwarf_P_Die dwarf_new_die(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Tag /*tag*/,
+ Dwarf_P_Die /*parent*/,
+ Dwarf_P_Die /*child*/,
+ Dwarf_P_Die /*left */,
+ Dwarf_P_Die /*right*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_die_to_debug(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Error* /*error*/);
+
+/* Markers are not written to DWARF2/3/4, they are user
+ defined and may be used for any purpose.
+*/
+Dwarf_Unsigned dwarf_add_die_marker(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*marker*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_Unsigned dwarf_get_die_marker(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned * /*marker*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_P_Die dwarf_die_link(
+ Dwarf_P_Die /*die*/,
+ Dwarf_P_Die /*parent*/,
+ Dwarf_P_Die /*child*/,
+ Dwarf_P_Die /*left*/,
+ Dwarf_P_Die /*right*/,
+ Dwarf_Error* /*error*/);
+
+void dwarf_dealloc_compressed_block(
+ Dwarf_P_Debug,
+ void *
+);
+
+/* Call this passing in return value from dwarf_uncompress_integer_block()
+ * to free the space the decompression allocated. */
+void dwarf_dealloc_uncompressed_block(
+ Dwarf_Debug,
+ void *
+);
+
+void * dwarf_compress_integer_block(
+ Dwarf_P_Debug, /* dbg */
+ Dwarf_Bool, /* signed==true (or unsigned) */
+ Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */
+ void*, /* data */
+ Dwarf_Unsigned, /* number of elements */
+ Dwarf_Unsigned*, /* number of bytes in output block */
+ Dwarf_Error* /* error */
+);
+
+/* Decode an array of signed leb integers (so of course the
+ * array is not composed of fixed length values, but is instead
+ * a sequence of sleb values).
+ * Returns a DW_DLV_BADADDR on error.
+ * Otherwise returns a pointer to an array of 32bit integers.
+ * The signed argument must be non-zero (the decode
+ * assumes sleb integers in the input data) at this time.
+ * Size of integer units must be 32 (32 bits each) at this time.
+ * Number of bytes in block is a byte count (not array count).
+ * Returns number of units in output block (ie, number of elements
+ * of the array that the return value points to) thru the argument.
+ */
+void * dwarf_uncompress_integer_block(
+ Dwarf_Debug, /* dbg */
+ Dwarf_Bool, /* signed==true (or unsigned) */
+ Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */
+ void*, /* input data */
+ Dwarf_Unsigned, /* number of bytes in input */
+ Dwarf_Unsigned*, /* number of units in output block */
+ Dwarf_Error* /* error */
+);
+
+/* Operations to create location expressions. */
+Dwarf_P_Expr dwarf_new_expr(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+void dwarf_expr_reset(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_gen(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Small /*opcode*/,
+ Dwarf_Unsigned /*val1*/,
+ Dwarf_Unsigned /*val2*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_addr(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned /*addr*/,
+ Dwarf_Signed /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_addr_b(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned /*addr*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_expr_current_offset(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Addr dwarf_expr_into_block(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_arange(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*begin_address*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Signed /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_arange_b(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*begin_address*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Unsigned /*end_symbol_index*/,
+ Dwarf_Addr /*offset_from_end_symbol*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_Unsigned dwarf_add_pubname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*pubname_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_funcname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*func_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_typename(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*type_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_varname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*var_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_weakname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*weak_name*/,
+ Dwarf_Error* /*error*/);
+
+/* .debug_macinfo producer functions
+ Functions must be called in right order: the section is output
+ In the order these are presented.
+*/
+int dwarf_def_macro(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*line*/,
+ char * /*macname, with (arglist), no space before (*/,
+ char * /*macvalue*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_undef_macro(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*line*/,
+ char * /*macname, no arglist, of course*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_start_macro_file(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*fileindex*/,
+ Dwarf_Unsigned /*linenumber*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_end_macro_file(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_vendor_ext(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*constant*/,
+ char * /*string*/,
+ Dwarf_Error* /*error*/);
+
+/* end macinfo producer functions */
+
+int dwarf_attr_offset(Dwarf_Die /*die*/,
+ Dwarf_Attribute /*attr of above die*/,
+ Dwarf_Off * /*returns offset thru this ptr */,
+ Dwarf_Error * /*error*/);
+
+/* This is a hack so clients can verify offsets.
+ Added April 2005 so that debugger can detect broken offsets
+ (which happened in an IRIX executable larger than 2GB
+ with MIPSpro 7.3.1.3 toolchain.).
+*/
+int
+dwarf_get_section_max_offsets(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned * /*debug_info_size*/,
+ Dwarf_Unsigned * /*debug_abbrev_size*/,
+ Dwarf_Unsigned * /*debug_line_size*/,
+ Dwarf_Unsigned * /*debug_loc_size*/,
+ Dwarf_Unsigned * /*debug_aranges_size*/,
+ Dwarf_Unsigned * /*debug_macinfo_size*/,
+ Dwarf_Unsigned * /*debug_pubnames_size*/,
+ Dwarf_Unsigned * /*debug_str_size*/,
+ Dwarf_Unsigned * /*debug_frame_size*/,
+ Dwarf_Unsigned * /*debug_ranges_size*/,
+ Dwarf_Unsigned * /*debug_pubtypes_size*/);
+
+/* Multiple releases spelled 'initial' as 'inital' .
+ The 'inital' spelling should not be used. */
+Dwarf_Half dwarf_set_frame_rule_inital_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+/* Additional interface with correct 'initial' spelling. */
+/* It is likely you will want to call the following 5 functions
+ before accessing any frame information. All are useful
+ to tailor handling of pseudo-registers needed to turn
+ frame operation references into simpler forms and to
+ reflect ABI specific data. Of course altering libdwarf.h
+ and dwarf.h allow the same capabilities, but such header changes
+ do not let one change these values at runtime. */
+Dwarf_Half dwarf_set_frame_rule_initial_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_rule_table_size(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_cfa_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_same_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_undefined_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+
+/* As of April 27, 2009, this version with no diepointer is
+ obsolete though supported. Use dwarf_get_ranges_a() instead. */
+int dwarf_get_ranges(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*rangesoffset*/,
+ Dwarf_Ranges ** /*rangesbuf*/,
+ Dwarf_Signed * /*listlen*/,
+ Dwarf_Unsigned * /*bytecount*/,
+ Dwarf_Error * /*error*/);
+
+/* This adds the address_size argument. New April 27, 2009 */
+int dwarf_get_ranges_a(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*rangesoffset*/,
+ Dwarf_Die /* diepointer */,
+ Dwarf_Ranges ** /*rangesbuf*/,
+ Dwarf_Signed * /*listlen*/,
+ Dwarf_Unsigned * /*bytecount*/,
+ Dwarf_Error * /*error*/);
+
+void dwarf_ranges_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Ranges * /*rangesbuf*/,
+ Dwarf_Signed /*rangecount*/);
+
+/* The harmless error list is a circular buffer of
+ errors we note but which do not stop us from processing
+ the object. Created so dwarfdump or other tools
+ can report such inconsequential errors without causing
+ anything to stop early. */
+#define DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE 4
+#define DW_HARMLESS_ERROR_MSG_STRING_SIZE 200
+/* User code supplies size of array of pointers errmsg_ptrs_array
+ in count and the array of pointers (the pointers themselves
+ need not be initialized).
+ The pointers returned in the array of pointers
+ are invalidated by ANY call to libdwarf.
+ Use them before making another libdwarf call!
+ The array of string pointers passed in always has
+ a final null pointer, so if there are N pointers the
+ and M actual strings, then MIN(M,N-1) pointers are
+ set to point to error strings. The array of pointers
+ to strings always terminates with a NULL pointer.
+ If 'count' is passed in zero then errmsg_ptrs_array
+ is not touched.
+
+ The function returns DW_DLV_NO_ENTRY if no harmless errors
+ were noted so far. Returns DW_DLV_OK if there are errors.
+ Never returns DW_DLV_ERROR.
+
+ Each call empties the error list (discarding all current entries).
+ If newerr_count is non-NULL the count of harmless errors
+ since the last call is returned through the pointer
+ (some may have been discarded or not returned, it is a circular
+ list...).
+ If DW_DLV_NO_ENTRY is returned none of the arguments
+ here are touched or used.
+ */
+int dwarf_get_harmless_error_list(Dwarf_Debug /*dbg*/,
+ unsigned /*count*/,
+ const char ** /*errmsg_ptrs_array*/,
+ unsigned * /*newerr_count*/);
+
+/* Insertion is only for testing the harmless error code, it is not
+ necessarily useful otherwise. */
+void dwarf_insert_harmless_error(Dwarf_Debug /*dbg*/,
+ char * /*newerror*/);
+
+/* The size of the circular list of strings may be set
+ and reset as needed. If it is shortened excess
+ messages are simply dropped. It returns the previous
+ size. If zero passed in the size is unchanged
+ and it simply returns the current size */
+unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug /*dbg*/,
+ unsigned /*maxcount*/);
+/* The harmless error strings (if any) are freed when the dbg
+ is dwarf_finish()ed. */
+
+/* When the val_in is known these dwarf_get_TAG_name (etc)
+ functions return the string corresponding to the val_in passed in
+ through the pointer s_out and the value returned is DW_DLV_OK.
+ The strings are in static storage
+ and must not be freed.
+ If DW_DLV_NO_ENTRY is returned the val_in is not known and
+ *s_out is not set. DW_DLV_ERROR is never returned.*/
+
+extern int dwarf_get_TAG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_children_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FORM_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_AT_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_OP_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_END_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATCF_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ACCESS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIRTUALITY_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LANG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ID_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_INL_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ORD_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DSC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_MACINFO_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CFA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_EH_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FRAME_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CHILDREN_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ADDR_name(unsigned int /*val_in*/, const char ** /*s_out */);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBDWARF_H */
+
+
diff --git a/usr/src/lib/libdwarf/common/libdwarfdefs.h b/usr/src/lib/libdwarf/common/libdwarfdefs.h
new file mode 100644
index 0000000000..a564655b23
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/libdwarfdefs.h
@@ -0,0 +1,91 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+/* libdwarfdefs.h
+*/
+
+#ifndef LIBDWARFDEFS_H
+#define LIBDWARFDEFS_H
+
+/* We want __uint32_t and __uint64_t and __int32_t __int64_t
+ properly defined but not duplicated, since duplicate typedefs
+ are not legal C.
+*/
+/*
+ HAVE___UINT32_T
+ HAVE___UINT64_T will be set by configure if
+ our 4 types are predefined in compiler
+*/
+
+
+#if (!defined(HAVE___UINT32_T)) && defined(HAVE___UINT32_T_IN_SGIDEFS_H)
+#include <sgidefs.h> /* sgidefs.h defines them */
+#define HAVE___UINT32_T 1
+#endif
+
+#if (!defined(HAVE___UINT64_T)) && defined(HAVE___UINT64_T_IN_SGIDEFS_H)
+#include <sgidefs.h> /* sgidefs.h defines them */
+#define HAVE___UINT64_T 1
+#endif
+
+
+#if (!defined(HAVE___UINT32_T)) && \
+ defined(HAVE_SYS_TYPES_H) && \
+ defined(HAVE___UINT32_T_IN_SYS_TYPES_H)
+# include <sys/types.h>
+#define HAVE___UINT32_T 1
+#endif
+
+#if (!defined(HAVE___UINT64_T)) && \
+ defined(HAVE_SYS_TYPES_H) && \
+ defined(HAVE___UINT64_T_IN_SYS_TYPES_H)
+# include <sys/types.h>
+#define HAVE___UINT64_T 1
+#endif
+
+#ifndef HAVE___UINT32_T
+typedef int __int32_t;
+typedef unsigned __uint32_t;
+#define HAVE___UINT32_T 1
+#endif
+
+#ifndef HAVE___UINT64_T
+typedef long long __int64_t;
+typedef unsigned long long __uint64_t;
+#define HAVE___UINT64_T 1
+#endif
+
+#endif /* LIBDWARFDEFS_H */
diff --git a/usr/src/lib/libdwarf/common/malloc_check.c b/usr/src/lib/libdwarf/common/malloc_check.c
new file mode 100644
index 0000000000..1c6e7738e4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/malloc_check.c
@@ -0,0 +1,339 @@
+/*
+
+ Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* malloc_check.c For checking dealloc completeness.
+
+ This code is as simple as possible and works ok for
+ reasonable size allocation counts.
+
+ It treats allocation as global, and so will not
+ work very well if an application opens more than one
+ Dwarf_Debug.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h> /* for exit() and various malloc
+ prototypes */
+#include "config.h"
+#include "dwarf_incl.h"
+#include "malloc_check.h"
+#ifdef WANT_LIBBDWARF_MALLOC_CHECK
+
+/* To turn off printing every entry, just change the define
+ to set PRINT_MALLOC_DETAILS 0.
+*/
+#define PRINT_MALLOC_DETAILS 0
+
+#define MC_TYPE_UNKNOWN 0
+#define MC_TYPE_ALLOC 1
+#define MC_TYPE_DEALLOC 2
+
+struct mc_data_s {
+ struct mc_data_s *mc_prev;
+ unsigned long mc_address; /* Assumes this is large enough to hold
+ a pointer! */
+
+ long mc_alloc_number; /* Assigned in order by when record
+ created. */
+ unsigned char mc_alloc_code; /* Allocation code, libdwarf. */
+ unsigned char mc_type;
+ unsigned char mc_dealloc_noted; /* Used on an ALLOC node. */
+ unsigned char mc_dealloc_noted_count; /* Used on an ALLOC
+ node. */
+};
+
+/*
+
+
+*/
+#define HASH_TABLE_SIZE 10501
+static struct mc_data_s *mc_data_hash[HASH_TABLE_SIZE];
+static long mc_data_list_size = 0;
+
+static char *alloc_type_name[MAX_DW_DLA + 1] = {
+ "",
+ "DW_DLA_STRING",
+ "DW_DLA_LOC",
+ "DW_DLA_LOCDESC",
+ "DW_DLA_ELLIST",
+ "DW_DLA_BOUNDS",
+ "DW_DLA_BLOCK",
+ "DW_DLA_DEBUG",
+ "DW_DLA_DIE",
+ "DW_DLA_LINE",
+ "DW_DLA_ATTR",
+ "DW_DLA_TYPE",
+ "DW_DLA_SUBSCR",
+ "DW_DLA_GLOBAL",
+ "DW_DLA_ERROR",
+ "DW_DLA_LIST",
+ "DW_DLA_LINEBUF",
+ "DW_DLA_ARANGE",
+ "DW_DLA_ABBREV",
+ "DW_DLA_FRAME_OP",
+ "DW_DLA_CIE",
+ "DW_DLA_FDE",
+ "DW_DLA_LOC_BLOCK",
+ "DW_DLA_FRAME_BLOCK",
+ "DW_DLA_FUNC",
+ "DW_DLA_TYPENAME",
+ "DW_DLA_VAR",
+ "DW_DLA_WEAK",
+ "DW_DLA_ADDR",
+ "DW_DLA_ABBREV_LIST",
+ "DW_DLA_CHAIN",
+ "DW_DLA_CU_CONTEXT",
+ "DW_DLA_FRAME",
+ "DW_DLA_GLOBAL_CONTEXT",
+ "DW_DLA_FILE_ENTRY",
+ "DW_DLA_LINE_CONTEXT",
+ "DW_DLA_LOC_CHAIN",
+ "DW_DLA_HASH_TABLE",
+ "DW_DLA_FUNC_CONTEXT",
+ "DW_DLA_TYPENAME_CONTEXT",
+ "DW_DLA_VAR_CONTEXT",
+ "DW_DLA_WEAK_CONTEXT",
+ "DW_DLA_PUBTYPES_CONTEXT"
+ /* Don't forget to expand this list if the list of codes
+ expands. */
+};
+
+static unsigned
+hash_address(unsigned long addr)
+{
+ unsigned long a = addr >> 2;
+
+ return a % HASH_TABLE_SIZE;
+}
+
+#if PRINT_MALLOC_DETAILS
+static void
+print_alloc_dealloc_detail(unsigned long addr,
+ int code, char *whichisit)
+{
+ fprintf(stderr,
+ "%s addr 0x%lx code %d (%s) entry %ld\n",
+ whichisit, addr, code, alloc_type_name[code],
+ mc_data_list_size);
+}
+#else
+#define print_alloc_dealloc_detail(a,b,c) /* nothing */
+#endif
+
+/* Create a zeroed struct or die. */
+static void *
+newone(void)
+{
+ struct mc_data_s *newd = malloc(sizeof(struct mc_data_s));
+
+ if (newd == 0) {
+ fprintf(stderr, "out of memory , # %ld\n", mc_data_list_size);
+ exit(1);
+ }
+ memset(newd, 0, sizeof(struct mc_data_s));
+ return newd;
+}
+
+/* Notify checker that get_alloc has allocated user data. */
+void
+dwarf_malloc_check_alloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+ print_alloc_dealloc_detail(addr, code, "alloc ");
+ newd->mc_address = addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_ALLOC;
+ newd->mc_alloc_number = mc_data_list_size;
+ newd->mc_prev = *base;
+ *base = newd;
+ newd->mc_alloc_number = mc_data_list_size;
+ mc_data_list_size += 1;
+}
+
+static void
+print_entry(char *msg, struct mc_data_s *data)
+{
+ fprintf(stderr,
+ "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n",
+ msg,
+ (long) data->mc_address,
+ data->mc_alloc_code,
+ alloc_type_name[data->mc_alloc_code],
+ (data->mc_type == MC_TYPE_ALLOC) ? "alloc " :
+ (data->mc_type == MC_TYPE_DEALLOC) ? "dealloc" : "unknown",
+ (unsigned) data->mc_dealloc_noted,
+ (unsigned) data->mc_dealloc_noted_count);
+}
+
+/* newd is a 'dealloc'.
+*/
+static long
+balanced_by_alloc_p(struct mc_data_s *newd,
+ long *addr_match_num,
+ struct mc_data_s **addr_match,
+ struct mc_data_s *base)
+{
+ struct mc_data_s *cur = base;
+
+ for (; cur; cur = cur->mc_prev) {
+ if (cur->mc_address == newd->mc_address) {
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_alloc_code == newd->mc_alloc_code) {
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return cur->mc_alloc_number;
+ } else {
+ /* code mismatch */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ } else {
+ /* Unbalanced new/del */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ }
+ }
+ return -1;
+}
+
+/* A dealloc is to take place. Ensure it balances an alloc.
+*/
+void
+dwarf_malloc_check_dealloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ long prev;
+ long addr_match_num = -1;
+ struct mc_data_s *addr_match = 0;
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+
+ print_alloc_dealloc_detail(addr, code, "dealloc ");
+ newd->mc_address = (unsigned long) addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_DEALLOC;
+ newd->mc_prev = *base;
+ prev =
+ balanced_by_alloc_p(newd, &addr_match_num, &addr_match, *base);
+ if (prev < 0) {
+ fprintf(stderr,
+ "Unbalanced dealloc at index %ld\n", mc_data_list_size);
+ print_entry("new", newd);
+ fprintf(stderr, "addr-match_num? %ld\n", addr_match_num);
+ if (addr_match) {
+ print_entry("prev entry", addr_match);
+ if (addr_match->mc_dealloc_noted > 1) {
+ fprintf(stderr, "Above is Duplicate dealloc!\n");
+ }
+ }
+ abort();
+ exit(3);
+ }
+ addr_match->mc_dealloc_noted = 1;
+ addr_match->mc_dealloc_noted_count += 1;
+ if (addr_match->mc_dealloc_noted_count > 1) {
+ fprintf(stderr, "Double dealloc entry %ld\n", addr_match_num);
+ print_entry("new dealloc entry", newd);
+ print_entry("bad alloc entry", addr_match);
+ }
+ *base = newd;
+ mc_data_list_size += 1;
+}
+
+/* Final check for leaks.
+*/
+void
+dwarf_malloc_check_complete(char *msg)
+{
+ long i = 0;
+ long total = mc_data_list_size;
+ long hash_slots_used = 0;
+ long max_chain_length = 0;
+
+ fprintf(stderr, "Run complete, %s. %ld entries\n", msg, total);
+ for (; i < HASH_TABLE_SIZE; ++i) {
+ struct mc_data_s *cur = mc_data_hash[i];
+ long cur_chain_length = 0;
+
+ if (cur == 0)
+ continue;
+ ++hash_slots_used;
+ for (; cur; cur = cur->mc_prev) {
+ ++cur_chain_length;
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_dealloc_noted) {
+ if (cur->mc_dealloc_noted > 1) {
+ fprintf(stderr,
+ " Duplicate dealloc! entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("duplicate dealloc", cur);
+
+ }
+ continue;
+ } else {
+ fprintf(stderr, "malloc no dealloc, entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("dangle", cur);
+ }
+ } else {
+ /* mc_type is MC_TYPE_DEALLOC, already checked */
+
+ }
+ }
+ if (cur_chain_length > max_chain_length) {
+ max_chain_length = cur_chain_length;
+ }
+ }
+ fprintf(stderr, "mc hash table slots=%ld, "
+ "used=%ld, maxchain=%ld\n",
+ (long) HASH_TABLE_SIZE, hash_slots_used, max_chain_length);
+ return;
+}
+
+#else
+
+extern void *libdwarf_an_unused_function_so_not_empty_c_file();
+
+#endif /* WANT_LIBBDWARF_MALLOC_CHECK */
diff --git a/usr/src/lib/libdwarf/common/malloc_check.h b/usr/src/lib/libdwarf/common/malloc_check.h
new file mode 100644
index 0000000000..ba1ad3da71
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/malloc_check.h
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+/* malloc_check.h */
+
+/* A simple libdwarf-aware malloc checker.
+ define WANT_LIBBDWARF_MALLOC_CHECK and rebuild libdwarf
+ do make a checking-for-alloc-mistakes libdwarf.
+ NOT recommended for production use.
+
+ When defined, also add malloc_check.c to the list of
+ files in Makefile.
+*/
+
+#undef WANT_LIBBDWARF_MALLOC_CHECK
+/*#define WANT_LIBBDWARF_MALLOC_CHECK 1 */
+
+#ifdef WANT_LIBBDWARF_MALLOC_CHECK
+
+void dwarf_malloc_check_alloc_data(void * addr,unsigned char code);
+void dwarf_malloc_check_dealloc_data(void * addr,unsigned char code);
+void dwarf_malloc_check_complete(char *wheremsg); /* called at exit of app */
+
+#else /* !WANT_LIBBDWARF_MALLOC_CHECK */
+
+#define dwarf_malloc_check_alloc_data(a,b) /* nothing */
+#define dwarf_malloc_check_dealloc_data(a,b) /* nothing */
+#define dwarf_malloc_check_complete(a) /* nothing */
+
+#endif /* WANT_LIBBDWARF_MALLOC_CHECK */
diff --git a/usr/src/lib/libdwarf/common/mapfile-vers b/usr/src/lib/libdwarf/common/mapfile-vers
new file mode 100644
index 0000000000..c1a652a591
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/mapfile-vers
@@ -0,0 +1,302 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2011, Richard Lowe.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate_1.1 {
+ global:
+ dwarf_add_arange;
+ dwarf_add_arange_b;
+ dwarf_add_AT_block;
+ dwarf_add_AT_comp_dir;
+ dwarf_add_AT_const_value_signedint;
+ dwarf_add_AT_const_value_string;
+ dwarf_add_AT_const_value_unsignedint;
+ dwarf_add_AT_dataref;
+ dwarf_add_AT_flag;
+ dwarf_add_AT_location_expr;
+ dwarf_add_AT_name;
+ dwarf_add_AT_producer;
+ dwarf_add_AT_ref_address;
+ dwarf_add_AT_reference;
+ dwarf_add_AT_signed_const;
+ dwarf_add_AT_string;
+ dwarf_add_AT_targ_address;
+ dwarf_add_AT_targ_address_b;
+ dwarf_add_AT_unsigned_const;
+ dwarf_add_die_marker;
+ dwarf_add_die_to_debug;
+ dwarf_add_directory_decl;
+ dwarf_add_expr_addr;
+ dwarf_add_expr_addr_b;
+ dwarf_add_expr_gen;
+ dwarf_add_fde_inst;
+ dwarf_add_file_decl;
+ dwarf_add_frame_cie;
+ dwarf_add_frame_fde;
+ dwarf_add_frame_fde_b;
+ dwarf_add_frame_info;
+ dwarf_add_frame_info_b;
+ dwarf_add_funcname;
+ dwarf_add_line_entry;
+ dwarf_add_pubname;
+ dwarf_add_typename;
+ dwarf_add_varname;
+ dwarf_add_weakname;
+ dwarf_arrayorder;
+ dwarf_attr;
+ dwarf_attr_offset;
+ dwarf_attrlist;
+ dwarf_bitoffset;
+ dwarf_bitsize;
+ dwarf_bytesize;
+ dwarf_check_lineheader;
+ dwarf_child;
+ dwarf_cie_section_offset;
+ dwarf_compress_integer_block;
+ dwarf_create_cie_from_after_start;
+ dwarf_create_fde_from_after_start;
+ dwarf_CU_dieoffset_given_die;
+ dwarf_dealloc;
+ dwarf_dealloc_compressed_block;
+ dwarf_dealloc_uncompressed_block;
+ dwarf_def_macro;
+ dwarf_die_abbrev_code;
+ dwarf_die_CU_offset;
+ dwarf_die_CU_offset_range;
+ dwarf_die_link;
+ dwarf_diename;
+ dwarf_dieoffset;
+ dwarf_elf_init;
+ dwarf_elf_object_access_finish;
+ dwarf_elf_object_access_init;
+ dwarf_end_macro_file;
+ dwarf_errmsg;
+ dwarf_errno;
+ dwarf_expand_frame_instructions;
+ dwarf_expr_current_offset;
+ dwarf_expr_into_block;
+ dwarf_expr_reset;
+ dwarf_fde_cfa_offset;
+ dwarf_fde_cie_list_dealloc;
+ dwarf_fde_section_offset;
+ dwarf_find_macro_value_start;
+ dwarf_finish;
+ dwarf_formaddr;
+ dwarf_formblock;
+ dwarf_formexprloc;
+ dwarf_formflag;
+ dwarf_formref;
+ dwarf_formsdata;
+ dwarf_formsig8;
+ dwarf_formstring;
+ dwarf_formudata;
+ dwarf_free_line_table_prefix;
+ dwarf_func_cu_offset;
+ dwarf_func_die_offset;
+ dwarf_func_name_offsets;
+ dwarf_funcname;
+ dwarf_funcs_dealloc;
+ dwarf_get_abbrev;
+ dwarf_get_abbrev_children_flag;
+ dwarf_get_abbrev_code;
+ dwarf_get_abbrev_entry;
+ dwarf_get_abbrev_tag;
+ dwarf_get_ACCESS_name;
+ dwarf_get_ADDR_name;
+ dwarf_get_address_size;
+ dwarf_get_arange;
+ dwarf_get_arange_cu_header_offset;
+ dwarf_get_arange_info;
+ dwarf_get_arange_info_b;
+ dwarf_get_aranges;
+ dwarf_get_AT_name;
+ dwarf_get_ATCF_name;
+ dwarf_get_ATE_name;
+ dwarf_get_CC_name;
+ dwarf_get_CFA_name;
+ dwarf_get_children_name;
+ dwarf_get_CHILDREN_name;
+ dwarf_get_cie_augmentation_data;
+ dwarf_get_cie_index;
+ dwarf_get_cie_info;
+ dwarf_get_cie_of_fde;
+ dwarf_get_cu_die_offset;
+ dwarf_get_cu_die_offset_given_cu_header_offset;
+ dwarf_get_die_address_size;
+ dwarf_get_die_marker;
+ dwarf_get_die_markers;
+ dwarf_get_DS_name;
+ dwarf_get_DSC_name;
+ dwarf_get_EH_name;
+ dwarf_get_elf;
+ dwarf_get_END_name;
+ dwarf_get_fde_at_pc;
+ dwarf_get_fde_augmentation_data;
+ dwarf_get_fde_exception_info;
+ dwarf_get_fde_for_die;
+ dwarf_get_fde_info_for_all_regs;
+ dwarf_get_fde_info_for_all_regs3;
+ dwarf_get_fde_info_for_cfa_reg3;
+ dwarf_get_fde_info_for_reg;
+ dwarf_get_fde_info_for_reg3;
+ dwarf_get_fde_instr_bytes;
+ dwarf_get_fde_list;
+ dwarf_get_fde_list_eh;
+ dwarf_get_fde_n;
+ dwarf_get_fde_range;
+ dwarf_get_form_class;
+ dwarf_get_FORM_name;
+ dwarf_get_FRAME_name;
+ dwarf_get_funcs;
+ dwarf_get_globals;
+ dwarf_get_harmless_error_list;
+ dwarf_get_ID_name;
+ dwarf_get_INL_name;
+ dwarf_get_ISA_name;
+ dwarf_get_LANG_name;
+ dwarf_get_LNE_name;
+ dwarf_get_LNS_name;
+ dwarf_get_loclist_entry;
+ dwarf_get_MACINFO_name;
+ dwarf_get_macro_details;
+ dwarf_get_OP_name;
+ dwarf_get_ORD_name;
+ dwarf_get_pubtypes;
+ dwarf_get_ranges;
+ dwarf_get_ranges_a;
+ dwarf_get_relocation_info;
+ dwarf_get_relocation_info_count;
+ dwarf_get_section_bytes;
+ dwarf_get_section_max_offsets;
+ dwarf_get_str;
+ dwarf_get_string_attributes_count;
+ dwarf_get_string_attributes_info;
+ dwarf_get_TAG_name;
+ dwarf_get_types;
+ dwarf_get_vars;
+ dwarf_get_VIRTUALITY_name;
+ dwarf_get_VIS_name;
+ dwarf_get_weaks;
+ dwarf_global_cu_offset;
+ dwarf_global_die_offset;
+ dwarf_global_formref;
+ dwarf_global_name_offsets;
+ dwarf_globals_dealloc;
+ dwarf_globname;
+ dwarf_harmless_cleanout;
+ dwarf_harmless_init;
+ dwarf_hasattr;
+ dwarf_hasform;
+ dwarf_highpc;
+ dwarf_init;
+ dwarf_init_line_table_prefix;
+ dwarf_insert_fde_inst_bytes;
+ dwarf_insert_harmless_error;
+ dwarf_ld_sort_lines;
+ dwarf_line_srcfileno;
+ dwarf_lineaddr;
+ dwarf_linebeginstatement;
+ dwarf_lineblock;
+ dwarf_lineendsequence;
+ dwarf_lineno;
+ dwarf_lineoff;
+ dwarf_linesrc;
+ dwarf_lne_end_sequence;
+ dwarf_lne_set_address;
+ dwarf_loclist;
+ dwarf_loclist_from_expr;
+ dwarf_loclist_from_expr_a;
+ dwarf_loclist_n;
+ dwarf_lowpc;
+ dwarf_new_die;
+ dwarf_new_expr;
+ dwarf_new_fde;
+ dwarf_next_cu_header;
+ dwarf_next_cu_header_b;
+ dwarf_nextglob;
+ dwarf_object_finish;
+ dwarf_object_init;
+ dwarf_offdie;
+ dwarf_p_dealloc;
+ dwarf_print_lines;
+ dwarf_print_memory_stats;
+ dwarf_producer_finish;
+ dwarf_producer_init;
+ dwarf_producer_init_b;
+ dwarf_pubtype_cu_offset;
+ dwarf_pubtype_name_offsets;
+ dwarf_pubtype_type_die_offset;
+ dwarf_pubtypename;
+ dwarf_pubtypes_dealloc;
+ dwarf_ranges_dealloc;
+ dwarf_read_cie_fde_prefix;
+ dwarf_read_line_table_prefix;
+ dwarf_reset_section_bytes;
+ dwarf_set_frame_cfa_value;
+ dwarf_set_frame_rule_inital_value;
+ dwarf_set_frame_rule_initial_value;
+ dwarf_set_frame_rule_table_size;
+ dwarf_set_frame_same_value;
+ dwarf_set_frame_undefined_value;
+ dwarf_set_harmless_error_list_size;
+ dwarf_set_reloc_application;
+ dwarf_set_stringcheck;
+ dwarf_siblingof;
+ dwarf_srcfiles;
+ dwarf_srclang;
+ dwarf_srclines;
+ dwarf_srclines_dealloc;
+ dwarf_start_macro_file;
+ dwarf_tag;
+ dwarf_transform_to_disk_form;
+ dwarf_type_cu_offset;
+ dwarf_type_die_offset;
+ dwarf_type_name_offsets;
+ dwarf_typename;
+ dwarf_types_dealloc;
+ dwarf_uncompress_integer_block;
+ dwarf_undef_macro;
+ dwarf_var_cu_offset;
+ dwarf_var_die_offset;
+ dwarf_var_name_offsets;
+ dwarf_varname;
+ dwarf_vars_dealloc;
+ dwarf_vendor_ext;
+ dwarf_weak_cu_offset;
+ dwarf_weak_die_offset;
+ dwarf_weak_name_offsets;
+ dwarf_weakname;
+ dwarf_weaks_dealloc;
+ dwarf_whatattr;
+ dwarf_whatform;
+ dwarf_whatform_direct;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_alloc.c b/usr/src/lib/libdwarf/common/pro_alloc.c
new file mode 100644
index 0000000000..1ca7806239
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_alloc.c
@@ -0,0 +1,188 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "pro_incl.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#include <malloc.h>
+
+/*
+ When each block is allocated, there is a two-word structure
+ allocated at the beginning so the block can go on a list.
+ The address returned is the address *after* the two pointers
+ at the start. But this allows us to be given a pointer to
+ a generic block, and go backwards to find the list-node. Then
+ we can remove this block from it's list without the need to search
+ through a linked list in order to remove the node. It also allows
+ us to 'delete' a memory block without needing the dbg structure.
+ We still need the dbg structure on allocation so that we know which
+ linked list to add the block to.
+
+ Only the allocation of the dbg structure itself cannot use _dwarf_p_get_alloc.
+ That structure should be set up by hand, and the two list pointers
+ should be initialized to point at the node itself. That initializes
+ the doubly linked list.
+*/
+
+#define LIST_TO_BLOCK(lst) ((void*) (((char *)lst) + sizeof(memory_list_t)))
+#define BLOCK_TO_LIST(blk) ((memory_list_t*) (((char*)blk) - sizeof(memory_list_t)))
+
+
+/*
+ dbg should be NULL only when allocating dbg itself. In that
+ case we initialize it to an empty circular doubly-linked list.
+*/
+
+Dwarf_Ptr
+_dwarf_p_get_alloc(Dwarf_P_Debug dbg, Dwarf_Unsigned size)
+{
+ void *sp;
+ memory_list_t *lp = NULL;
+ memory_list_t *dbglp = NULL;
+ memory_list_t *nextblock = NULL;
+
+ /* alloc control struct and data block together for performance reasons */
+ lp = (memory_list_t *) malloc(size + sizeof(memory_list_t));
+ if (lp == NULL) {
+ /* should throw an error */
+ return NULL;
+ }
+
+ /* point to 'size' bytes just beyond lp struct */
+ sp = LIST_TO_BLOCK(lp);
+ memset(sp, 0, size);
+
+ if (dbg == NULL) {
+ lp->next = lp->prev = lp;
+ } else {
+ /* I always have to draw a picture to understand this part. */
+
+ dbglp = BLOCK_TO_LIST(dbg);
+ nextblock = dbglp->next;
+
+ /* Insert between dbglp and nextblock */
+ dbglp->next = lp;
+ lp->prev = dbglp;
+ lp->next = nextblock;
+ nextblock->prev = lp;
+ }
+
+ return sp;
+}
+
+/*
+ This routine is only here in case a caller of an older version of the
+ library is calling this for some reason.
+ We will clean up any stray blocks when the session is closed.
+ No need to remove this block. In theory the user might be
+ depending on the fact that we used to just 'free' this.
+ In theory they might also be
+ passing a block that they got from libdwarf. So we don't know if we
+ should try to remove this block from our global list. Safest just to
+ do nothing at this point.
+
+ !!!
+ This function is deprecated! Don't call it inside libdwarf or outside of it.
+ !!!
+*/
+
+void
+dwarf_p_dealloc(Dwarf_Small * ptr)
+{
+ return;
+}
+
+/*
+ The dbg structure is not needed here anymore.
+*/
+
+void
+_dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr) /* ARGSUSED */
+{
+ memory_list_t *lp;
+ lp = BLOCK_TO_LIST(ptr);
+
+ /*
+ Remove from a doubly linked, circular list.
+ Read carefully, use a white board if necessary.
+ If this is an empty list, the following statements are no-ops, and
+ will write to the same memory location they read from.
+ This should only happen when we deallocate the dbg structure itself.
+ */
+
+ lp->prev->next = lp->next;
+ lp->next->prev = lp->prev;
+
+ free((void*)lp);
+}
+
+
+/*
+ This routine deallocates all the nodes on the dbg list,
+ and then deallocates the dbg structure itself.
+*/
+
+void
+_dwarf_p_dealloc_all(Dwarf_P_Debug dbg)
+{
+ memory_list_t *dbglp;
+
+ if (dbg == NULL) {
+ /* should throw an error */
+ return;
+ }
+
+ dbglp = BLOCK_TO_LIST(dbg);
+ while (dbglp->next != dbglp) {
+ _dwarf_p_dealloc(dbg, LIST_TO_BLOCK(dbglp->next));
+ }
+ if (dbglp->next != dbglp ||
+ dbglp->prev != dbglp) {
+
+ /* should throw error */
+ /* For some reason we couldn't free all the blocks? */
+ return;
+ }
+ _dwarf_p_dealloc(NULL, (void*)dbg);
+}
+
diff --git a/usr/src/lib/libdwarf/common/pro_alloc.h b/usr/src/lib/libdwarf/common/pro_alloc.h
new file mode 100644
index 0000000000..b4da65325f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_alloc.h
@@ -0,0 +1,42 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+Dwarf_Ptr _dwarf_p_get_alloc(Dwarf_P_Debug, Dwarf_Unsigned);
+
+void _dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr);
+
+void _dwarf_p_dealloc_all(Dwarf_P_Debug dbg);
diff --git a/usr/src/lib/libdwarf/common/pro_arange.c b/usr/src/lib/libdwarf/common/pro_arange.c
new file mode 100644
index 0000000000..4e5c37795c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_arange.c
@@ -0,0 +1,337 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_arange.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+
+
+
+/*
+ This function adds another address range
+ to the list of address ranges for the
+ given Dwarf_P_Debug. It returns 0 on error,
+ and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_arange(Dwarf_P_Debug dbg,
+ Dwarf_Addr begin_address,
+ Dwarf_Unsigned length,
+ Dwarf_Signed symbol_index, Dwarf_Error * error)
+{
+ return dwarf_add_arange_b(dbg, begin_address, length, symbol_index,
+ /* end_symbol_index */ 0,
+ /* offset_from_end_sym */ 0,
+ error);
+}
+
+/*
+ This function adds another address range
+ to the list of address ranges for the
+ given Dwarf_P_Debug. It returns 0 on error,
+ and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_arange_b(Dwarf_P_Debug dbg,
+ Dwarf_Addr begin_address,
+ Dwarf_Unsigned length,
+ Dwarf_Unsigned symbol_index,
+ Dwarf_Unsigned end_symbol_index,
+ Dwarf_Addr offset_from_end_sym, Dwarf_Error * error)
+{
+ Dwarf_P_Arange arange;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (0);
+ }
+
+ arange = (Dwarf_P_Arange)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Arange_s));
+ if (arange == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ arange->ag_begin_address = begin_address;
+ arange->ag_length = length;
+ arange->ag_symbol_index = symbol_index;
+ arange->ag_end_symbol_index = end_symbol_index;
+ arange->ag_end_symbol_offset = offset_from_end_sym;
+
+ if (dbg->de_arange == NULL)
+ dbg->de_arange = dbg->de_last_arange = arange;
+ else {
+ dbg->de_last_arange->ag_next = arange;
+ dbg->de_last_arange = arange;
+ }
+ dbg->de_arange_count++;
+
+ return (1);
+}
+
+
+int
+_dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ /* Total num of bytes in .debug_aranges section. */
+ Dwarf_Unsigned arange_num_bytes;
+
+ /*
+ Adjustment to align the start of the actual address ranges on a
+ boundary aligned with twice the address size. */
+ Dwarf_Small remainder;
+
+ /* Total number of bytes excluding the length field. */
+ Dwarf_Unsigned adjusted_length;
+
+ /* Points to first byte of .debug_aranges buffer. */
+ Dwarf_Small *arange;
+
+ /* Fills in the .debug_aranges buffer. */
+ Dwarf_Small *arange_ptr;
+
+ /* Scans the list of address ranges provided by user. */
+ Dwarf_P_Arange given_arange;
+
+ /* Used to fill in 0. */
+ const Dwarf_Signed big_zero = 0;
+
+ int extension_word_size = dbg->de_64bit_extension ? 4 : 0;
+ int uword_size = dbg->de_offset_size;
+ int upointer_size = dbg->de_pointer_size;
+ int res;
+
+
+ /* ***** BEGIN CODE ***** */
+
+ /* Size of the .debug_aranges section header. */
+ arange_num_bytes = extension_word_size + uword_size + /* Size
+ of
+ length
+ field.
+ */
+ sizeof(Dwarf_Half) + /* Size of version field. */
+ uword_size + /* Size of .debug_info offset. */
+ sizeof(Dwarf_Small) + /* Size of address size field. */
+ sizeof(Dwarf_Small); /* Size of segment size field. */
+
+ /*
+ Adjust the size so that the set of aranges begins on a boundary
+ that aligned with twice the address size. This is a Libdwarf
+ requirement. */
+ remainder = arange_num_bytes % (2 * upointer_size);
+ if (remainder != 0)
+ arange_num_bytes += (2 * upointer_size) - remainder;
+
+
+ /* Add the bytes for the actual address ranges. */
+ arange_num_bytes += upointer_size * 2 * (dbg->de_arange_count + 1);
+
+ GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_ARANGES],
+ arange, (unsigned long) arange_num_bytes, error);
+ arange_ptr = arange;
+ if (arange == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ if (extension_word_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &x,
+ sizeof(x), extension_word_size);
+ arange_ptr += extension_word_size;
+ }
+
+ /* Write the total length of .debug_aranges section. */
+ adjusted_length = arange_num_bytes - uword_size
+ - extension_word_size;
+ {
+ Dwarf_Unsigned du = adjusted_length;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &du, sizeof(du), uword_size);
+ arange_ptr += uword_size;
+ }
+
+ /* Write the version as 2 bytes. */
+ {
+ Dwarf_Half verstamp = CURRENT_VERSION_STAMP;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &verstamp,
+ sizeof(verstamp), sizeof(Dwarf_Half));
+ arange_ptr += sizeof(Dwarf_Half);
+ }
+
+
+ /* Write the .debug_info offset. This is always 0. */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+ arange_ptr += uword_size;
+
+ {
+ unsigned long count = dbg->de_arange_count + 1;
+ int res;
+
+ if (dbg->de_reloc_pair) {
+ count = (3 * dbg->de_arange_count) + 1;
+ }
+ /* the following is a small optimization: not needed for
+ correctness */
+ res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg,
+ DEBUG_ARANGES, count);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+ }
+
+ /* reloc for .debug_info */
+ res = dbg->de_reloc_name(dbg,
+ DEBUG_ARANGES,
+ extension_word_size +
+ uword_size + sizeof(Dwarf_Half),
+ dbg->de_sect_name_idx[DEBUG_INFO],
+ dwarf_drt_data_reloc, uword_size);
+
+ /* Write the size of addresses. */
+ *arange_ptr = dbg->de_pointer_size;
+ arange_ptr++;
+
+ /*
+ Write the size of segment addresses. This is zero for MIPS
+ architectures. */
+ *arange_ptr = 0;
+ arange_ptr++;
+
+ /*
+ Skip over the padding to align the start of the actual address
+ ranges to twice the address size. */
+ if (remainder != 0)
+ arange_ptr += (2 * upointer_size) - remainder;
+
+
+
+
+
+ /* The arange address, length are pointer-size fields of the target
+ machine. */
+ for (given_arange = dbg->de_arange; given_arange != NULL;
+ given_arange = given_arange->ag_next) {
+
+ /* Write relocation record for beginning of address range. */
+ res = dbg->de_reloc_name(dbg, DEBUG_ARANGES, arange_ptr - arange, /* r_offset
+ */
+ (long) given_arange->ag_symbol_index,
+ dwarf_drt_data_reloc, upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* Copy beginning address of range. */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &given_arange->ag_begin_address,
+ sizeof(given_arange->ag_begin_address),
+ upointer_size);
+ arange_ptr += upointer_size;
+
+ if (dbg->de_reloc_pair &&
+ given_arange->ag_end_symbol_index != 0 &&
+ given_arange->ag_length == 0) {
+ /* symbolic reloc, need reloc for length What if we really
+ know the length? If so, should use the other part of
+ 'if'. */
+ Dwarf_Unsigned val;
+
+ res = dbg->de_reloc_pair(dbg, DEBUG_ARANGES, arange_ptr - arange, /* r_offset
+ */
+ given_arange->ag_symbol_index,
+ given_arange->ag_end_symbol_index,
+ dwarf_drt_first_of_length_pair,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* arrange pre-calc so assem text can do .word end - begin
+ + val (gets val from stream) */
+ val = given_arange->ag_end_symbol_offset -
+ given_arange->ag_begin_address;
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &val,
+ sizeof(val), upointer_size);
+ arange_ptr += upointer_size;
+
+ } else {
+ /* plain old length to copy, no relocation at all */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &given_arange->ag_length,
+ sizeof(given_arange->ag_length),
+ upointer_size);
+ arange_ptr += upointer_size;
+ }
+ }
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), upointer_size);
+
+ arange_ptr += upointer_size;
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), upointer_size);
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_arange.h b/usr/src/lib/libdwarf/common/pro_arange.h
new file mode 100644
index 0000000000..f0e7e84dff
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_arange.h
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+/*
+ If ag_end_symbol_index is zero,
+ ag_length must be known and non-zero.
+
+
+ Deals with length being known costant or fr
+ assembler output, not known.
+
+*/
+
+struct Dwarf_P_Arange_s {
+ Dwarf_Addr ag_begin_address; /* known address or for
+ symbolic assem output,
+ offset of symbol */
+ Dwarf_Addr ag_length; /* zero or address or offset */
+ Dwarf_Unsigned ag_symbol_index;
+
+ Dwarf_P_Arange ag_next;
+
+ Dwarf_Unsigned ag_end_symbol_index; /* zero or index/id of end
+ symbol */
+ Dwarf_Addr ag_end_symbol_offset; /* known address or for
+ symbolic assem output,
+ offset of end symbol */
+
+};
diff --git a/usr/src/lib/libdwarf/common/pro_die.c b/usr/src/lib/libdwarf/common/pro_die.c
new file mode 100644
index 0000000000..948b641146
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_die.c
@@ -0,0 +1,442 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_die.h"
+
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+/* adds an attribute to a die */
+void _dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr);
+
+/*----------------------------------------------------------------------------
+ This function creates a new die.
+ tag: tag of the new die to be created
+ parent,child,left,right: specify neighbors of the new die. Only
+ one of these may be non-null
+-----------------------------------------------------------------------------*/
+Dwarf_P_Die
+dwarf_new_die(Dwarf_P_Debug dbg,
+ Dwarf_Tag tag,
+ Dwarf_P_Die parent,
+ Dwarf_P_Die child,
+ Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
+{
+ Dwarf_P_Die ret_die = 0;
+
+ Dwarf_P_Die new_die = (Dwarf_P_Die)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Die_s));
+ if (new_die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_ALLOC,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ new_die->di_parent = NULL;
+ new_die->di_left = NULL;
+ new_die->di_right = NULL;
+ new_die->di_child = NULL;
+ new_die->di_last_child = NULL;
+ new_die->di_tag = tag;
+ new_die->di_dbg = dbg;
+ new_die->di_marker = 0;
+ ret_die =
+ dwarf_die_link(new_die, parent, child, left, right, error);
+ return ret_die;
+}
+
+/*----------------------------------------------------------------------------
+ This function links up a die to specified neighbors
+ parent,child,left,right: specify neighbors of the new die. Only
+ one of these may be non-null
+-----------------------------------------------------------------------------*/
+Dwarf_P_Die
+dwarf_die_link(Dwarf_P_Die new_die,
+ Dwarf_P_Die parent,
+ Dwarf_P_Die child,
+ Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
+{
+ /* Count the # of non null neighbors. */
+ int n_nulls = 0;
+
+ if (parent != NULL) {
+ n_nulls++;
+ if (new_die->di_parent != NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_LINK_LOOP,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ new_die->di_parent = parent;
+ if (parent->di_child) {
+
+ /* di_last_child identifies the last sibling, the
+ die we want to attach new_die to. */
+ /* ASSERT: if di_child is set so is di_last_child. */
+ Dwarf_P_Die former_lastchild = parent->di_last_child;
+ parent->di_last_child = new_die;
+ /* Attach to the new die to end of the sibling list. */
+ former_lastchild->di_right = new_die;
+ new_die->di_left = former_lastchild;
+ } else {
+ parent->di_child = new_die;
+ parent->di_last_child = new_die;
+ }
+ }
+ if (child != NULL) {
+ n_nulls++;
+ new_die->di_child = child;
+ new_die->di_last_child = child;
+ if (child->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ child->di_parent = new_die;
+ }
+ }
+ if (left != NULL) {
+ n_nulls++;
+ new_die->di_left = left;
+ if (left->di_right) {
+ /* There's already a right sibling of left,
+ insert the new die in the list. */
+ new_die->di_right = left->di_right;
+ left->di_right->di_left = new_die;
+ }
+ left->di_right = new_die;
+ if (new_die->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ new_die->di_parent = left->di_parent;
+ }
+ }
+ if (right != NULL) {
+ n_nulls++;
+ new_die->di_right = right;
+ if (right->di_left) {
+ /* There is already a left sibling of the right die,
+ insert the new die in the list. */
+ new_die->di_left = right->di_left;
+ right->di_left->di_right = new_die;
+ }
+ right->di_left = new_die;
+ if (new_die->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ new_die->di_parent = right->di_parent;
+ }
+ }
+ if (n_nulls > 1) {
+ /* Multiple neighbors! error! */
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_EXTRA_NEIGHBORS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ return new_die;
+
+}
+
+Dwarf_Unsigned
+dwarf_add_die_marker(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned marker,
+ Dwarf_Error * error)
+{
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ die->di_marker = marker;
+ return 0;
+}
+
+
+Dwarf_Unsigned
+dwarf_get_die_marker(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned * marker,
+ Dwarf_Error * error)
+{
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ *marker = die->di_marker;
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ This function adds a die to dbg struct. It should be called using
+ the root of all the dies.
+-----------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_die_to_debug(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die, Dwarf_Error * error)
+{
+ if (first_die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ if (first_die->di_tag != DW_TAG_compile_unit) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_TAG, DW_DLV_NOCOUNT);
+ }
+ dbg->de_dies = first_die;
+ return 0;
+}
+
+int
+_dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ /* Add AT_stmt_list attribute */
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, DW_DLV_NOCOUNT);
+ }
+
+ new_attr->ar_attribute = DW_AT_stmt_list;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = 0;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(first_die, new_attr);
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ Add AT_name attribute to die
+------------------------------------------------------------------------------*/
+Dwarf_P_Attribute
+dwarf_add_AT_name(Dwarf_P_Die die, char *name, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(die->di_dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_name;
+ /* assume that form is string, no debug_str yet */
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(name) + 1;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = 0;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(die->di_dbg, strlen(name)+1);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ strcpy(new_attr->ar_data, name);
+
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(die, new_attr);
+ return new_attr;
+}
+
+
+/*-----------------------------------------------------------------------------
+ Add AT_comp_dir attribute to die
+------------------------------------------------------------------------------*/
+Dwarf_P_Attribute
+dwarf_add_AT_comp_dir(Dwarf_P_Die ownerdie,
+ char *current_working_directory,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg,
+ sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_comp_dir;
+ /* assume that form is string, no debug_str yet */
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(current_working_directory) + 1;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = 0;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg,
+ strlen(current_working_directory)+1);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ strcpy(new_attr->ar_data, current_working_directory);
+
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+int
+_dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_MIPS_fde;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = offset;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(die, new_attr);
+
+ return 0;
+}
+
+int
+_dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_macro_info;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = offset;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(die, new_attr);
+
+ return 0;
+}
+
+
+void
+_dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr)
+{
+ if (die->di_last_attr) {
+ die->di_last_attr->ar_next = attr;
+ die->di_last_attr = attr;
+ die->di_n_attr++;
+ } else {
+ die->di_n_attr = 1;
+ die->di_attrs = die->di_last_attr = attr;
+ }
+}
diff --git a/usr/src/lib/libdwarf/common/pro_die.h b/usr/src/lib/libdwarf/common/pro_die.h
new file mode 100644
index 0000000000..01c00e79bd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_die.h
@@ -0,0 +1,68 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+/*
+ This struct holds the abbreviation table, before they are written
+ on disk. Holds a linked list of abbreviations, each consisting of
+ a bitmap for attributes and a bitmap for forms
+*/
+typedef struct Dwarf_P_Abbrev_s *Dwarf_P_Abbrev;
+
+struct Dwarf_P_Abbrev_s {
+ Dwarf_Unsigned abb_idx; /* index of abbreviation */
+ Dwarf_Tag abb_tag; /* tag of die */
+ Dwarf_Ubyte abb_children; /* if children are present */
+ Dwarf_ufixed *abb_attrs; /* holds names of attrs */
+ Dwarf_ufixed *abb_forms; /* forms of attributes */
+ int abb_n_attr; /* num of attrs = # of forms */
+ Dwarf_P_Abbrev abb_next;
+};
+
+/* used in pro_section.c */
+
+int _dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg, Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error);
+
+int _dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die,
+ Dwarf_Error * error);
+
+int _dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die,
+ Dwarf_Unsigned offset,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_encode_nm.c b/usr/src/lib/libdwarf/common/pro_encode_nm.c
new file mode 100644
index 0000000000..d6215dc56b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_encode_nm.c
@@ -0,0 +1,123 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <string.h>
+#include "pro_incl.h"
+
+#define MORE_BYTES 0x80
+#define DATA_MASK 0x7f
+#define DIGIT_WIDTH 7
+#define SIGN_BIT 0x40
+
+
+/*-------------------------------------------------------------
+ Encode val as a leb128. This encodes it as an unsigned
+ number.
+---------------------------------------------------------------*/
+/* return DW_DLV_ERROR or DW_DLV_OK.
+** space to write leb number is provided by caller, with caller
+** passing length.
+** number of bytes used returned thru nbytes arg
+*/
+int
+_dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes,
+ char *space, int splen)
+{
+ char *a;
+ char *end = space + splen;
+
+ a = space;
+ do {
+ unsigned char uc;
+
+ if (a >= end) {
+ return DW_DLV_ERROR;
+ }
+ uc = val & DATA_MASK;
+ val >>= DIGIT_WIDTH;
+ if (val != 0) {
+ uc |= MORE_BYTES;
+ }
+ *a = uc;
+ a++;
+ } while (val);
+ *nbytes = a - space;
+ return DW_DLV_OK;
+}
+
+/* return DW_DLV_ERROR or DW_DLV_OK.
+** space to write leb number is provided by caller, with caller
+** passing length.
+** number of bytes used returned thru nbytes arg
+** encodes a signed number.
+*/
+int
+_dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes,
+ char *space, int splen)
+{
+ char *str;
+ Dwarf_Signed sign = -(value < 0);
+ int more = 1;
+ char *end = space + splen;
+
+ str = space;
+
+ do {
+ unsigned char byte = value & DATA_MASK;
+
+ value >>= DIGIT_WIDTH;
+
+ if (str >= end) {
+ return DW_DLV_ERROR;
+ }
+ /*
+ * Remaining chunks would just contain the sign bit, and this chunk
+ * has already captured at least one sign bit.
+ */
+ if (value == sign && ((byte & SIGN_BIT) == (sign & SIGN_BIT))) {
+ more = 0;
+ } else {
+ byte |= MORE_BYTES;
+ }
+ *str = byte;
+ str++;
+ } while (more);
+ *nbytes = str - space;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_encode_nm.h b/usr/src/lib/libdwarf/common/pro_encode_nm.h
new file mode 100644
index 0000000000..d08e4d5148
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_encode_nm.h
@@ -0,0 +1,48 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/* Bytes needed to encode a number.
+ Not a tight bound, just a reasonable bound.
+*/
+#define ENCODE_SPACE_NEEDED (2*sizeof(Dwarf_Unsigned))
+
+
+int _dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes,
+ char *space, int splen);
+
+int _dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes,
+ char *space, int splen);
diff --git a/usr/src/lib/libdwarf/common/pro_error.c b/usr/src/lib/libdwarf/common/pro_error.c
new file mode 100644
index 0000000000..d408a391e2
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_error.c
@@ -0,0 +1,97 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "pro_incl.h"
+
+extern char *_dwarf_errmsgs[];
+
+/*
+ This function performs error handling as described in the
+ libdwarf consumer document section 3. Dbg is the Dwarf_P_debug
+ structure being processed. Error is a pointer to the pointer
+ to the error descriptor that will be returned. Errval is an
+ error code listed in dwarf_error.h.
+*/
+void
+_dwarf_p_error(Dwarf_P_Debug dbg,
+ Dwarf_Error * error, Dwarf_Word errval)
+{
+ Dwarf_Error errptr;
+
+ /* Allow NULL dbg on entry, since sometimes that can happen and we
+ want to report the upper-level error, not this one. */
+ if ((Dwarf_Sword) errval < 0)
+ printf("ERROR VALUE: %ld - %s\n",
+ (long) errval, _dwarf_errmsgs[-errval - 1]);
+ if (error != NULL) {
+ errptr = (Dwarf_Error)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s));
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure\n");
+ abort();
+ }
+ errptr->er_errval = (Dwarf_Sword) errval;
+ *error = errptr;
+ return;
+ }
+
+ if (dbg != NULL && dbg->de_errhand != NULL) {
+ errptr = (Dwarf_Error)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s));
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure\n");
+ abort();
+ }
+ errptr->er_errval = (Dwarf_Sword) errval;
+ dbg->de_errhand(errptr, dbg->de_errarg);
+ return;
+ }
+
+ abort();
+}
diff --git a/usr/src/lib/libdwarf/common/pro_error.h b/usr/src/lib/libdwarf/common/pro_error.h
new file mode 100644
index 0000000000..c37035301b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_error.h
@@ -0,0 +1,52 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+/* Handle error passing in the name of the Dwarf_P_Debug
+ User must supply {} around the macro.
+ Putting the {} here leads to macro uses that don't look like C.
+ The error argument to dwarf_error is hard coded here as 'error'
+*/
+#define DWARF_P_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_p_error(dbg,error,errval); return(retval);
+
+struct Dwarf_Error_s {
+ Dwarf_Sword er_errval;
+};
+
+void _dwarf_p_error(Dwarf_P_Debug dbg, Dwarf_Error * error,
+ Dwarf_Word errval);
diff --git a/usr/src/lib/libdwarf/common/pro_expr.c b/usr/src/lib/libdwarf/common/pro_expr.c
new file mode 100644
index 0000000000..ad40eb762a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_expr.c
@@ -0,0 +1,597 @@
+/*
+
+ Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "pro_incl.h"
+#include "pro_expr.h"
+
+/*
+ This function creates a new expression
+ struct that can be used to build up a
+ location expression.
+*/
+Dwarf_P_Expr
+dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Expr ret_expr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (NULL);
+ }
+
+ ret_expr = (Dwarf_P_Expr)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Expr_s));
+ if (ret_expr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ ret_expr->ex_dbg = dbg;
+
+ return (ret_expr);
+}
+
+
+Dwarf_Unsigned
+dwarf_add_expr_gen(Dwarf_P_Expr expr,
+ Dwarf_Small opcode,
+ Dwarf_Unsigned val1,
+ Dwarf_Unsigned val2, Dwarf_Error * error)
+{
+ char encode_buffer[2 * ENCODE_SPACE_NEEDED]; /* 2* since
+ used to
+ concatenate
+ 2 leb's
+ below */
+ char encode_buffer2[ENCODE_SPACE_NEEDED];
+ int res;
+ Dwarf_P_Debug dbg = expr->ex_dbg;
+
+ /*
+ Give the buffer where the operands are first going to be
+ assembled the largest alignment. */
+ Dwarf_Unsigned operand_buffer[10];
+
+ /*
+ Size of the byte stream buffer that needs to be memcpy-ed. */
+ int operand_size;
+
+ /*
+ Points to the byte stream for the first operand, and finally to
+ the buffer that is memcp-ed into the Dwarf_P_Expr_s struct. */
+ Dwarf_Small *operand;
+
+ /* Size of the byte stream for second operand. */
+ int operand2_size;
+
+ /* Points to next byte to be written in Dwarf_P_Expr_s struct. */
+ Dwarf_Small *next_byte_ptr;
+
+ /* Offset past the last byte written into Dwarf_P_Expr_s. */
+ int next_byte_offset;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ operand = NULL;
+ operand_size = 0;
+
+ switch (opcode) {
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_regx:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ break;
+
+ case DW_OP_addr:
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2);
+ operand_size = 2;
+ break;
+
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4);
+ operand_size = 4;
+ break;
+
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 8);
+ operand_size = 8;
+ break;
+
+ case DW_OP_constu:
+ res = _dwarf_pro_encode_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_consts:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_fbreg:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_bregx:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ /* put this one directly into 'operand' at tail of prev value */
+ res = _dwarf_pro_encode_signed_leb128_nm(val2, &operand2_size,
+ ((char *) operand) +
+ operand_size,
+ sizeof
+ (encode_buffer2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand_size += operand2_size;
+
+ case DW_OP_dup:
+ case DW_OP_drop:
+ break;
+
+ case DW_OP_pick:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, (const void *) &val1,
+ sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ case DW_OP_xderef:
+ break;
+
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, (const void *) &val1,
+ sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ break;
+
+ case DW_OP_plus_uconst:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ break;
+
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ break;
+
+ case DW_OP_skip:
+ case DW_OP_bra:
+ /* FIX: unhandled! OP_bra, OP_skip! */
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+
+ case DW_OP_piece:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_nop:
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2);
+ operand_size = 2;
+ break;
+
+ case DW_OP_call4: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4);
+ operand_size = 4;
+ break;
+
+ case DW_OP_call_ref: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1),
+ dbg->de_offset_size);
+ operand_size = dbg->de_offset_size;
+ break;
+ case DW_OP_form_tls_address: /* DWARF3f */
+ break;
+ case DW_OP_call_frame_cfa: /* DWARF3f */
+ break;
+ case DW_OP_bit_piece: /* DWARF3f */
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ /* put this one directly into 'operand' at tail of prev value */
+ res = _dwarf_pro_encode_leb128_nm(val2, &operand2_size,
+ ((char *) operand) +
+ operand_size,
+ sizeof(encode_buffer2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand_size += operand2_size;
+ break;
+
+ default:
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_offset = expr->ex_next_byte_offset + operand_size + 1;
+
+ if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_ptr =
+ &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset;
+
+ *next_byte_ptr = opcode;
+ next_byte_ptr++;
+ memcpy(next_byte_ptr, operand, operand_size);
+
+ expr->ex_next_byte_offset = next_byte_offset;
+ return (next_byte_offset);
+}
+
+Dwarf_Unsigned
+dwarf_add_expr_addr_b(Dwarf_P_Expr expr,
+ Dwarf_Unsigned addr,
+ Dwarf_Unsigned sym_index, Dwarf_Error * error)
+{
+ Dwarf_P_Debug dbg;
+ Dwarf_Small *next_byte_ptr;
+ Dwarf_Unsigned next_byte_offset;
+ int upointer_size;
+
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ dbg = expr->ex_dbg;
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ upointer_size = dbg->de_pointer_size;
+ next_byte_offset = expr->ex_next_byte_offset + upointer_size + 1;
+ if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) {
+ _dwarf_p_error(dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_ptr =
+ &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset;
+
+ *next_byte_ptr = DW_OP_addr;
+ next_byte_ptr++;
+ WRITE_UNALIGNED(dbg, next_byte_ptr, (const void *) &addr,
+ sizeof(addr), upointer_size);
+
+ if (expr->ex_reloc_offset != 0) {
+ _dwarf_p_error(dbg, error, DW_DLE_MULTIPLE_RELOC_IN_EXPR);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ expr->ex_reloc_sym_index = sym_index;
+ expr->ex_reloc_offset = expr->ex_next_byte_offset + 1;
+
+ expr->ex_next_byte_offset = next_byte_offset;
+ return (next_byte_offset);
+}
+
+Dwarf_Unsigned
+dwarf_add_expr_addr(Dwarf_P_Expr expr,
+ Dwarf_Unsigned addr,
+ Dwarf_Signed sym_index, Dwarf_Error * error)
+{
+ return
+ dwarf_add_expr_addr_b(expr, addr, (Dwarf_Unsigned) sym_index,
+ error);
+}
+
+
+Dwarf_Unsigned
+dwarf_expr_current_offset(Dwarf_P_Expr expr, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ return (expr->ex_next_byte_offset);
+}
+
+void
+dwarf_expr_reset(Dwarf_P_Expr expr, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return;
+ }
+ expr->ex_next_byte_offset=0;
+}
+
+
+Dwarf_Addr
+dwarf_expr_into_block(Dwarf_P_Expr expr,
+ Dwarf_Unsigned * length, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_BADADDR);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_BADADDR);
+ }
+
+ if (length != NULL)
+ *length = expr->ex_next_byte_offset;
+ /* The following cast from pointer to integer is ok as long as
+ Dwarf_Addr is at least as large as a pointer. Which is a
+ requirement of libdwarf so must be satisfied (some compilers
+ emit a warning about the following line). */
+ return ((Dwarf_Addr)(uintptr_t) &(expr->ex_byte_stream[0]));
+}
diff --git a/usr/src/lib/libdwarf/common/pro_expr.h b/usr/src/lib/libdwarf/common/pro_expr.h
new file mode 100644
index 0000000000..202f2d30d5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_expr.h
@@ -0,0 +1,45 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#define MAXIMUM_LOC_EXPR_LENGTH 20
+
+struct Dwarf_P_Expr_s {
+ Dwarf_Small ex_byte_stream[MAXIMUM_LOC_EXPR_LENGTH];
+ Dwarf_P_Debug ex_dbg;
+ Dwarf_Unsigned ex_next_byte_offset;
+ Dwarf_Unsigned ex_reloc_sym_index;
+ Dwarf_Unsigned ex_reloc_offset;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_finish.c b/usr/src/lib/libdwarf/common/pro_finish.c
new file mode 100644
index 0000000000..bc43a5f0f4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_finish.c
@@ -0,0 +1,57 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include "pro_incl.h"
+
+/*---------------------------------------------------------------
+ This routine deallocates all memory, and does some
+ finishing up
+-----------------------------------------------------------------*/
+ /*ARGSUSED*/ Dwarf_Unsigned
+dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT);
+ }
+
+ /* this frees all blocks, then frees dbg. */
+ _dwarf_p_dealloc_all(dbg);
+ return 0;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_forms.c b/usr/src/lib/libdwarf/common/pro_forms.c
new file mode 100644
index 0000000000..fec9a39c60
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_forms.c
@@ -0,0 +1,1182 @@
+/*
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2007-2010 David Anderson. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "pro_incl.h"
+#include "pro_expr.h"
+
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+
+ /* Indicates no relocation needed. */
+#define NO_ELF_SYM_INDEX 0
+
+
+/* adds an attribute to a die */
+extern void _dwarf_pro_add_at_to_die(Dwarf_P_Die die,
+ Dwarf_P_Attribute attr);
+
+/*
+ This function adds an attribute whose value is
+ a target address to the given die. The attribute
+ is given the name provided by attr. The address
+ is given in pc_value.
+*/
+
+static Dwarf_P_Attribute
+local_add_AT_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed form,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error);
+
+/* old interface */
+Dwarf_P_Attribute
+dwarf_add_AT_targ_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Signed sym_index, Dwarf_Error * error)
+{
+ return
+ dwarf_add_AT_targ_address_b(dbg,
+ ownerdie,
+ attr,
+ pc_value,
+ (Dwarf_Unsigned) sym_index, error);
+}
+
+/* New interface, replacing dwarf_add_AT_targ_address.
+ Essentially just makes sym_index a Dwarf_Unsigned
+ so for symbolic relocations it can be a full address.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_targ_address_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ switch (attr) {
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+
+ /* added to support location lists */
+ /* no way to check that this is a loclist-style address though */
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_const_value: /* Gcc can generate this as address. */
+ case DW_AT_entry_pc:
+ break;
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_addr,
+ pc_value, sym_index, error);
+}
+
+Dwarf_P_Attribute
+dwarf_add_AT_ref_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ switch (attr) {
+ case DW_AT_type:
+ case DW_AT_import:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_ref_addr,
+ pc_value, sym_index, error);
+}
+
+
+/* Make sure attribute types are checked before entering here. */
+static Dwarf_P_Attribute
+local_add_AT_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed form,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int upointer_size = dbg->de_pointer_size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* attribute types have already been checked */
+ /* switch (attr) { ... } */
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = form;
+ new_attr->ar_nbytes = upointer_size;
+ new_attr->ar_rel_symidx = sym_index;
+ new_attr->ar_reloc_len = upointer_size;
+ new_attr->ar_next = 0;
+ if (sym_index != NO_ELF_SYM_INDEX)
+ new_attr->ar_rel_type = dbg->de_ptr_reloc;
+ else
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, upointer_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &pc_value,
+ sizeof(pc_value), upointer_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+/*
+ * Functions to compress and uncompress data from normal
+ * arrays of integral types into arrays of LEB128 numbers.
+ * Extend these functions as needed to handle wider input
+ * variety. Return values should be freed with _dwarf_p_dealloc
+ * after they aren't needed any more.
+ */
+
+/* return value points to an array of LEB number */
+
+void *
+dwarf_compress_integer_block(
+ Dwarf_P_Debug dbg,
+ Dwarf_Bool unit_is_signed,
+ Dwarf_Small unit_length_in_bits,
+ void* input_block,
+ Dwarf_Unsigned input_length_in_units,
+ Dwarf_Unsigned* output_length_in_bytes_ptr,
+ Dwarf_Error* error
+)
+{
+ Dwarf_Unsigned output_length_in_bytes = 0;
+ char * output_block = 0;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int i = 0;
+ char * ptr = 0;
+ int remain = 0;
+ int result = 0;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ if (unit_is_signed == false ||
+ unit_length_in_bits != 32 ||
+ input_block == NULL ||
+ input_length_in_units == 0 ||
+ output_length_in_bytes_ptr == NULL) {
+
+ _dwarf_p_error(NULL, error, DW_DLE_BADBITC);
+ return ((void *) DW_DLV_BADADDR);
+ }
+
+ /* At this point we assume the format is: signed 32 bit */
+
+ /* first compress everything to find the total size. */
+
+ output_length_in_bytes = 0;
+ for (i=0; i<input_length_in_units; i++) {
+ int unit_encoded_size;
+ Dwarf_sfixed unit; /* this is fixed at signed-32-bits */
+
+ unit = ((Dwarf_sfixed*)input_block)[i];
+
+ result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size,
+ encode_buffer,sizeof(encode_buffer));
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+ output_length_in_bytes += unit_encoded_size;
+ }
+
+
+ /* then alloc */
+
+ output_block = (void *)
+ _dwarf_p_get_alloc(dbg, output_length_in_bytes);
+ if (output_block == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((void*)DW_DLV_BADADDR);
+ }
+
+ /* then compress again and copy into new buffer */
+
+ ptr = output_block;
+ remain = output_length_in_bytes;
+ for (i=0; i<input_length_in_units; i++) {
+ int unit_encoded_size;
+ Dwarf_sfixed unit; /* this is fixed at signed-32-bits */
+
+ unit = ((Dwarf_sfixed*)input_block)[i];
+
+ result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size,
+ ptr, remain);
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+ remain -= unit_encoded_size;
+ ptr += unit_encoded_size;
+ }
+
+ if (remain != 0) {
+ _dwarf_p_dealloc(dbg, (unsigned char *)output_block);
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ *output_length_in_bytes_ptr = output_length_in_bytes;
+ return (void*) output_block;
+
+}
+
+void
+dwarf_dealloc_compressed_block(Dwarf_P_Debug dbg, void * space)
+{
+ _dwarf_p_dealloc(dbg, space);
+}
+
+/* This is very similar to targ_address but results in a different FORM */
+/* dbg->de_ar_data_attribute_form is data4 or data8
+ and dwarf4 changes the definition for such on DW_AT_high_pc.
+ DWARF 3: the FORM here has no defined meaning for dwarf3.
+ DWARF 4: the FORM here means that for DW_AT_high_pc the value
+ is not a high address but is instead an offset
+ from a (separate) DW_AT_low_pc.
+ The intent for DWARF4 is that this is not a relocated
+ address at all. Instead a simple offset.
+ But this should NOT be called for a simple non-relocated offset.
+ So do not call this with an attr of DW_AT_high_pc.
+ Use dwarf_add_AT_unsigned_const() (for example) instead of
+ dwarf_add_AT_dataref when the value is a simple offset .
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_dataref(
+ Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ /* TODO: Add checking here */
+ return local_add_AT_address(dbg, ownerdie, attr,
+ dbg->de_ar_data_attribute_form,
+ pc_value,
+ sym_index,
+ error);
+}
+
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_block(
+ Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Small *block_data,
+ Dwarf_Unsigned block_size,
+ Dwarf_Error *error
+)
+{
+ Dwarf_P_Attribute new_attr;
+ int result;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int len_size;
+ char * attrdata;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* I don't mess with block1, block2, block4, not worth the effort */
+
+ /* So, encode the length into LEB128 */
+ result = _dwarf_pro_encode_leb128_nm(block_size, &len_size,
+ encode_buffer,sizeof(encode_buffer));
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* Allocate the new attribute */
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* Fill in the attribute */
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_block;
+ new_attr->ar_nbytes = len_size + block_size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = attrdata = (char *)
+ _dwarf_p_get_alloc(dbg, len_size + block_size);
+ if (new_attr->ar_data == NULL) {
+ /* free the block we got earlier */
+ _dwarf_p_dealloc(dbg, (unsigned char *) new_attr);
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* write length and data to attribute data buffer */
+ memcpy(attrdata, encode_buffer, len_size);
+ attrdata += len_size;
+ memcpy(attrdata, block_data, block_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is an unsigned constant. It determines the
+ size of the value field from the value of
+ the constant.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_unsigned_const(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ Dwarf_Small size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_ordering:
+ case DW_AT_byte_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_inline:
+ case DW_AT_language:
+ case DW_AT_visibility:
+ case DW_AT_virtuality:
+ case DW_AT_accessibility:
+ case DW_AT_address_class:
+ case DW_AT_calling_convention:
+ case DW_AT_encoding:
+ case DW_AT_identifier_case:
+ case DW_AT_MIPS_loop_unroll_factor:
+ case DW_AT_MIPS_software_pipeline_depth:
+ break;
+
+ case DW_AT_decl_column:
+ case DW_AT_decl_file:
+ case DW_AT_decl_line:
+ case DW_AT_const_value:
+ case DW_AT_start_scope:
+ case DW_AT_stride_size:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_upper_bound:
+ case DW_AT_lower_bound:
+ case DW_AT_call_file:
+ case DW_AT_call_line:
+ break;
+
+ default: {
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (value <= UCHAR_MAX) {
+ attr_form = DW_FORM_data1;
+ size = 1;
+ } else if (value <= USHRT_MAX) {
+ attr_form = DW_FORM_data2;
+ size = 2;
+ } else if (value <= UINT_MAX) {
+ attr_form = DW_FORM_data4;
+ size = 4;
+ } else {
+ attr_form = DW_FORM_data8;
+ size = 8;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */
+ new_attr->ar_nbytes = size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &value, sizeof(value), size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is an signed constant. It determines the
+ size of the value field from the value of
+ the constant.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_signed_const(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ Dwarf_Small size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_const_value:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_byte_size:
+ case DW_AT_count:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_stride:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ break;
+
+ default:{
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ }
+ break;
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (value >= SCHAR_MIN && value <= SCHAR_MAX) {
+ attr_form = DW_FORM_data1;
+ size = 1;
+ } else if (value >= SHRT_MIN && value <= SHRT_MAX) {
+ attr_form = DW_FORM_data2;
+ size = 2;
+ } else if (value >= INT_MIN && value <= INT_MAX) {
+ attr_form = DW_FORM_data4;
+ size = 4;
+ } else {
+ attr_form = DW_FORM_data8;
+ size = 8;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */
+ new_attr->ar_nbytes = size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &value, sizeof(value), size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is a location expression.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_location_expr(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_P_Expr loc_expr, Dwarf_Error * error)
+{
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ char *len_str = 0;
+ int len_size;
+ int block_size;
+ char *block_dest_ptr;
+ int do_len_as_int = 0;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (loc_expr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_EXPR_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (loc_expr->ex_dbg != dbg) {
+ _dwarf_p_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ block_size = loc_expr->ex_next_byte_offset;
+
+ switch (attr) {
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_const_value:
+ case DW_AT_use_location:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_static_link:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_data_location:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_size:
+ case DW_AT_bit_size:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (block_size <= UCHAR_MAX) {
+ attr_form = DW_FORM_block1;
+ len_size = 1;
+ do_len_as_int = 1;
+ } else if (block_size <= USHRT_MAX) {
+ attr_form = DW_FORM_block2;
+ len_size = 2;
+ do_len_as_int = 1;
+ } else if (block_size <= UINT_MAX) {
+ attr_form = DW_FORM_block4;
+ len_size = 4;
+ do_len_as_int = 1;
+ } else {
+ attr_form = DW_FORM_block;
+ res = _dwarf_pro_encode_leb128_nm(block_size, &len_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ len_str = (char *) encode_buffer;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_reloc_len = dbg->de_pointer_size;
+ if (loc_expr->ex_reloc_sym_index != NO_ELF_SYM_INDEX) {
+ new_attr->ar_rel_type = dbg->de_ptr_reloc;
+ } else {
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ }
+ new_attr->ar_rel_symidx = loc_expr->ex_reloc_sym_index;
+ new_attr->ar_rel_offset =
+ (Dwarf_Word) loc_expr->ex_reloc_offset + len_size;
+
+ new_attr->ar_nbytes = block_size + len_size;
+
+ new_attr->ar_next = 0;
+ new_attr->ar_data = block_dest_ptr =
+ (char *) _dwarf_p_get_alloc(dbg, block_size + len_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (do_len_as_int) {
+ WRITE_UNALIGNED(dbg, block_dest_ptr, (const void *) &block_size,
+ sizeof(block_size), len_size);
+ } else {
+ /* Is uleb number form, DW_FORM_block. See above. */
+ memcpy(block_dest_ptr, len_str, len_size);
+ }
+ block_dest_ptr += len_size;
+ memcpy(block_dest_ptr, &(loc_expr->ex_byte_stream[0]), block_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes of reference class.
+ The references here are local CU references,
+ not DW_FORM_ref_addr.
+ The offset field is 4 bytes for 32-bit objects,
+ and 8-bytes for 64-bit objects. Otherdie is the
+ that is referenced by ownerdie.
+
+ For reference attributes, the ar_data and ar_nbytes
+ are not needed. Instead, the ar_ref_die points to
+ the other die, and its di_offset value is used as
+ the reference value.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_reference(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_P_Die otherdie, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (otherdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_specification:
+ case DW_AT_discr:
+ case DW_AT_common_reference:
+ case DW_AT_import:
+ case DW_AT_containing_type:
+ case DW_AT_default_value:
+ case DW_AT_abstract_origin:
+ case DW_AT_friend:
+ case DW_AT_priority:
+ case DW_AT_type:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_byte_size:
+ case DW_AT_sibling:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_stride:
+ case DW_AT_namelist_item:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = dbg->de_ar_ref_attr_form;
+ new_attr->ar_nbytes = dbg->de_offset_size;
+ new_attr->ar_reloc_len = dbg->de_offset_size;
+ new_attr->ar_ref_die = otherdie;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_next = 0;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes of the flag class.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_flag(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Small flag, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+#if 0
+ switch (attr) {
+ case DW_AT_is_optional:
+ case DW_AT_artificial:
+ case DW_AT_declaration:
+ case DW_AT_external:
+ case DW_AT_prototyped:
+ case DW_AT_variable_parameter:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+#endif
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_flag;
+ new_attr->ar_nbytes = 1;
+ new_attr->ar_reloc_len = 0; /* not used */
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, 1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, &flag, 1);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds values of attributes
+ belonging to the string class.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_string(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr, char *string, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_name:
+ case DW_AT_comp_dir:
+ case DW_AT_const_value:
+ case DW_AT_producer:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(string) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(dbg, strlen(string)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, string);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_string(Dwarf_P_Die ownerdie,
+ char *string_value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(string_value) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(string_value)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, string_value);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_producer(Dwarf_P_Die ownerdie,
+ char *producer_string, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_producer;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(producer_string) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(producer_string)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, producer_string);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_signedint(Dwarf_P_Die ownerdie,
+ Dwarf_Signed signed_value,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int leb_size;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_sdata;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+ new_attr->ar_next = 0;
+
+ res = _dwarf_pro_encode_signed_leb128_nm(signed_value, &leb_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, encode_buffer, leb_size);
+ new_attr->ar_nbytes = leb_size;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_unsignedint(Dwarf_P_Die ownerdie,
+ Dwarf_Unsigned unsigned_value,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int leb_size;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_udata;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+ new_attr->ar_next = 0;
+
+ res = _dwarf_pro_encode_leb128_nm(unsigned_value, &leb_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, encode_buffer, leb_size);
+ new_attr->ar_nbytes = leb_size;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_frame.c b/usr/src/lib/libdwarf/common/pro_frame.c
new file mode 100644
index 0000000000..bd1ef6a637
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_frame.c
@@ -0,0 +1,598 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "pro_incl.h"
+#include "pro_frame.h"
+
+static void _dwarf_pro_add_to_fde(Dwarf_P_Fde fde,
+ Dwarf_P_Frame_Pgm inst);
+
+/*-------------------------------------------------------------------------
+ This function adds a cie struct to the debug pointer. Its in the
+ form of a linked list.
+ augmenter: string reps augmentation (implementation defined)
+ code_align: alignment of code
+ data_align: alignment of data
+ init_bytes: byts having initial instructions
+ init_n_bytes: number of bytes of initial instructions
+--------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_frame_cie(Dwarf_P_Debug dbg,
+ char *augmenter,
+ Dwarf_Small code_align,
+ Dwarf_Small data_align,
+ Dwarf_Small return_reg,
+ Dwarf_Ptr init_bytes,
+ Dwarf_Unsigned init_n_bytes, Dwarf_Error * error)
+{
+ Dwarf_P_Cie curcie;
+
+ if (dbg->de_frame_cies == NULL) {
+ dbg->de_frame_cies = (Dwarf_P_Cie)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
+ if (dbg->de_frame_cies == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ curcie = dbg->de_frame_cies;
+ dbg->de_n_cie = 1;
+ dbg->de_last_cie = curcie;
+ } else {
+ curcie = dbg->de_last_cie;
+ curcie->cie_next = (Dwarf_P_Cie)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
+ if (curcie->cie_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ curcie = curcie->cie_next;
+ dbg->de_n_cie++;
+ dbg->de_last_cie = curcie;
+ }
+ curcie->cie_version = DW_CIE_VERSION;
+ curcie->cie_aug = augmenter;
+ curcie->cie_code_align = code_align;
+ curcie->cie_data_align = data_align;
+ curcie->cie_ret_reg = return_reg;
+ curcie->cie_inst = (char *) init_bytes;
+ curcie->cie_inst_bytes = (long) init_n_bytes;
+ curcie->cie_next = NULL;
+ return dbg->de_n_cie;
+}
+
+
+/*-------------------------------------------------------------------------
+ This functions adds a fde struct to the debug pointer. Its in the
+ form of a linked list.
+ die: subprogram/function die corresponding to this fde
+ cie: cie referred to by this fde, obtained from call to
+ add_frame_cie() routine.
+ virt_addr: beginning address
+ code_len: length of code reps by the fde
+--------------------------------------------------------------------------*/
+ /*ARGSUSED*/ /* pretend all args used */
+ Dwarf_Unsigned
+dwarf_add_frame_fde(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx, Dwarf_Error * error)
+{
+ return dwarf_add_frame_fde_b(dbg, fde, die, cie, virt_addr,
+ code_len, symidx, 0, 0, error);
+}
+
+/*ARGSUSED10*/
+Dwarf_Unsigned
+dwarf_add_frame_fde_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned symidx_of_end,
+ Dwarf_Addr offset_from_end_sym,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Fde curfde;
+
+ fde->fde_die = die;
+ fde->fde_cie = (long) cie;
+ fde->fde_initloc = virt_addr;
+ fde->fde_r_symidx = symidx;
+ fde->fde_addr_range = code_len;
+ fde->fde_offset_into_exception_tables = DW_DLX_NO_EH_OFFSET;
+ fde->fde_exception_table_symbol = 0;
+ fde->fde_end_symbol_offset = offset_from_end_sym;
+ fde->fde_end_symbol = symidx_of_end;
+ fde->fde_dbg = dbg;
+
+ curfde = dbg->de_last_fde;
+ if (curfde == NULL) {
+ dbg->de_frame_fdes = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde = 1;
+ } else {
+ curfde->fde_next = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde++;
+ }
+ return dbg->de_n_fde;
+}
+
+/*-------------------------------------------------------------------------
+ This functions adds information to an fde. The fde is
+ linked into the linked list of fde's maintained in the Dwarf_P_Debug
+ structure.
+ dbg: The debug descriptor.
+ fde: The fde to be added.
+ die: subprogram/function die corresponding to this fde
+ cie: cie referred to by this fde, obtained from call to
+ add_frame_cie() routine.
+ virt_addr: beginning address
+ code_len: length of code reps by the fde
+ symidx: The symbol id of the symbol wrt to which relocation needs
+ to be performed for 'virt_addr'.
+ offset_into_exception_tables: The start of exception tables for
+ this function (indicated as an offset into the exception
+ tables). A value of -1 indicates that there is no exception
+ table entries associated with this function.
+ exception_table_symbol: The symbol id of the section for exception
+ tables wrt to which the offset_into_exception_tables will
+ be relocated.
+--------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_frame_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Signed offset_into_exception_tables,
+ Dwarf_Unsigned exception_table_symbol,
+ Dwarf_Error * error)
+{
+
+ return dwarf_add_frame_info_b(dbg, fde, die, cie, virt_addr,
+ code_len, symidx,
+ /* end_symbol */ 0,
+ /* offset_from_end */ 0,
+ offset_into_exception_tables,
+ exception_table_symbol, error);
+
+}
+
+ /*ARGSUSED*/ /* pretend all args used */
+Dwarf_Unsigned
+dwarf_add_frame_info_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned end_symidx,
+ Dwarf_Unsigned offset_from_end_symbol,
+ Dwarf_Signed offset_into_exception_tables,
+ Dwarf_Unsigned exception_table_symbol,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Fde curfde;
+
+ fde->fde_die = die;
+ fde->fde_cie = (long) cie;
+ fde->fde_initloc = virt_addr;
+ fde->fde_r_symidx = symidx;
+ fde->fde_addr_range = code_len;
+ fde->fde_offset_into_exception_tables =
+ offset_into_exception_tables;
+ fde->fde_exception_table_symbol = exception_table_symbol;
+ fde->fde_end_symbol_offset = offset_from_end_symbol;
+ fde->fde_end_symbol = end_symidx;
+ fde->fde_dbg = dbg;
+
+ curfde = dbg->de_last_fde;
+ if (curfde == NULL) {
+ dbg->de_frame_fdes = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde = 1;
+ } else {
+ curfde->fde_next = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde++;
+ }
+ return dbg->de_n_fde;
+}
+
+/* This is an alternate to inserting frame instructions
+ one instruction at a time. But use either this
+ or instruction level, not both in one fde. */
+int
+dwarf_insert_fde_inst_bytes(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,Dwarf_Unsigned len, Dwarf_Ptr ibytes,
+ Dwarf_Error *error)
+{
+ if( len == 0) {
+ return DW_DLV_OK;
+ }
+ if(fde->fde_block || fde->fde_inst) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DUPLICATE_INST_BLOCK,
+ (int)DW_DLV_BADADDR);
+ }
+ fde->fde_block = (Dwarf_Ptr)_dwarf_p_get_alloc(dbg, len);
+ memcpy(fde->fde_block,ibytes,len);
+ fde->fde_inst_block_size = len;
+ fde->fde_n_bytes += len;
+ return DW_DLV_OK;
+}
+
+
+
+/*-------------------------------------------------------------------
+ Create a new fde.
+---------------------------------------------------------------------*/
+Dwarf_P_Fde
+dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Fde fde;
+
+ fde = (Dwarf_P_Fde)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Fde_s));
+ if (fde == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FDE_ALLOC,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ fde->fde_uwordb_size = dbg->de_offset_size;
+
+ return fde;
+}
+
+
+/*------------------------------------------------------------------------
+ Add a cfe_offset instruction to the fde passed in.
+-------------------------------------------------------------------------*/
+Dwarf_P_Fde
+dwarf_fde_cfa_offset(Dwarf_P_Fde fde,
+ Dwarf_Unsigned reg,
+ Dwarf_Signed offset, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc, regno;
+ char *ptr;
+ Dwarf_P_Frame_Pgm curinst;
+ int nbytes;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+ Dwarf_P_Debug dbg = fde->fde_dbg;
+
+ curinst = (Dwarf_P_Frame_Pgm)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
+ if (curinst == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FPGM_ALLOC,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ opc = DW_CFA_offset;
+ regno = reg;
+ if (regno & 0xc0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REGNO_OVFL,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ opc = opc | regno; /* lower 6 bits are register number */
+ curinst->dfp_opcode = opc;
+ res = _dwarf_pro_encode_leb128_nm(offset, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+
+ curinst->dfp_args = ptr;
+ curinst->dfp_nbytes = nbytes;
+ curinst->dfp_next = NULL;
+
+ _dwarf_pro_add_to_fde(fde, curinst);
+ return fde;
+}
+
+/*
+ Generic routine to add opcode to fde instructions. val1 and
+ val2 are parameters whose interpretation depends on the 'op'.
+
+ This does not work properly for DW_DLC_SYMBOLIC_RELOCATIONS
+ for DW_CFA_set_loc or DW_DVA_advance_loc* 'op', as
+ these ops normally are addresses or (DW_CFA_set_loc)
+ or code lengths (DW_DVA_advance_loc*) and such must be
+ represented with relocations and symbol indices for
+ DW_DLC_SYMBOLIC_RELOCATIONS.
+
+ This does not treat all DW_CFA instructions yet.
+
+ For certain operations a val? value must be
+ signed (though passed in as unsigned here).
+
+ Currently this does not check that the frame
+ version is 3(for dwarf3) or 4 (for dwarf4)
+ when applying operations that are only valid for
+ dwarf3 or dwarf4.
+
+*/
+Dwarf_P_Fde
+dwarf_add_fde_inst(Dwarf_P_Fde fde,
+ Dwarf_Small op,
+ Dwarf_Unsigned val1,
+ Dwarf_Unsigned val2, Dwarf_Error * error)
+{
+ Dwarf_P_Frame_Pgm curinst;
+ int nbytes, nbytes1, nbytes2;
+ Dwarf_Ubyte db;
+ Dwarf_Half dh;
+ Dwarf_Word dw;
+ Dwarf_Unsigned du;
+ char *ptr;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+ char buff2[ENCODE_SPACE_NEEDED];
+ Dwarf_P_Debug dbg = fde->fde_dbg;
+ /* This is a hack telling the code when to transform
+ a value to a signed leb number. */
+ int signed_second = 0;
+ int signed_first = 0;
+
+
+ nbytes = 0;
+ ptr = NULL;
+ curinst = (Dwarf_P_Frame_Pgm)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
+ if (curinst == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_FPGM_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ switch (op) {
+
+ case DW_CFA_advance_loc:
+ if (val1 <= 0x3f) {
+ db = val1;
+ op |= db;
+ }
+ /* test not portable FIX */
+ else if (val1 <= UCHAR_MAX) {
+ op = DW_CFA_advance_loc1;
+ db = val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 1);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &db, 1);
+ nbytes = 1;
+ }
+ /* test not portable FIX */
+ else if (val1 <= USHRT_MAX) {
+ op = DW_CFA_advance_loc2;
+ dh = val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 2);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &dh, 2);
+ nbytes = 2;
+ }
+ /* test not portable FIX */
+ else if (val1 <= ULONG_MAX) {
+ op = DW_CFA_advance_loc4;
+ dw = (Dwarf_Word) val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 4);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &dw, 4);
+ nbytes = 4;
+ } else {
+ op = DW_CFA_MIPS_advance_loc8;
+ du = val1;
+ ptr =
+ (char *) _dwarf_p_get_alloc(dbg,
+ sizeof(Dwarf_Unsigned));
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &du, 8);
+ nbytes = 8;
+ }
+ break;
+
+ case DW_CFA_offset:
+ if (val1 <= MAX_6_BIT_VALUE) {
+ db = val1;
+ op |= db;
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+
+ } else {
+ op = DW_CFA_offset_extended;
+ goto two_leb;
+ }
+ break;
+ case DW_CFA_offset_extended_sf: /* DWARF3 */
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_offset_extended:
+ goto two_leb;
+
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ goto one_leb;
+
+ case DW_CFA_val_offset:
+ goto two_leb;
+ case DW_CFA_val_offset_sf:
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_def_cfa_sf:
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ two_leb:
+ res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ if (!signed_second) {
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
+ buff2, sizeof(buff2));
+ } else {
+ Dwarf_Signed val2s = val2;
+ res = _dwarf_pro_encode_signed_leb128_nm(val2s, &nbytes2,
+ buff2, sizeof(buff2));
+ }
+
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
+ buff2, sizeof(buff2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes1 + nbytes2);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes1);
+ memcpy(ptr + nbytes1, buff2, nbytes2);
+ nbytes = nbytes1 + nbytes2;
+ break;
+
+ case DW_CFA_def_cfa_offset_sf: /* DWARF3 */
+ signed_first = 1;
+ goto one_leb;
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ one_leb:
+ if(!signed_first) {
+ res = _dwarf_pro_encode_leb128_nm(val1, &nbytes,
+ buff1, sizeof(buff1));
+ } else {
+ Dwarf_Signed val1s = val1;
+ res = _dwarf_pro_encode_signed_leb128_nm(val1s, &nbytes,
+ buff1, sizeof(buff1));
+ }
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+ break;
+ case DW_CFA_def_cfa_expression: /* DWARF3 */
+ /* FIXME: argument is dwarf expr, not handled yet. */
+ case DW_CFA_expression: /* DWARF3 */
+ /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
+ FIXME: not handled yet. */
+ case DW_CFA_val_expression: /* DWARF3f */
+ /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
+ FIXME: not handled yet. */
+ default:
+ _dwarf_p_error(dbg, error, DW_DLE_DEBUGFRAME_ERROR);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ curinst->dfp_opcode = op;
+ curinst->dfp_args = ptr;
+ curinst->dfp_nbytes = nbytes;
+ curinst->dfp_next = NULL;
+
+ _dwarf_pro_add_to_fde(fde, curinst);
+ return fde;
+}
+
+
+/*------------------------------------------------------------------------
+ Instructions are added to an fde in the form of a linked
+ list. This function manages the linked list.
+-------------------------------------------------------------------------*/
+void
+_dwarf_pro_add_to_fde(Dwarf_P_Fde fde, Dwarf_P_Frame_Pgm curinst)
+{
+ if (fde->fde_last_inst) {
+ fde->fde_last_inst->dfp_next = curinst;
+ fde->fde_last_inst = curinst;
+ fde->fde_n_inst++;
+ fde->fde_n_bytes +=
+ (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
+ } else {
+ fde->fde_last_inst = curinst;
+ fde->fde_inst = curinst;
+ fde->fde_n_inst = 1;
+ fde->fde_n_bytes =
+ (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
+ }
+}
diff --git a/usr/src/lib/libdwarf/common/pro_frame.h b/usr/src/lib/libdwarf/common/pro_frame.h
new file mode 100644
index 0000000000..df60d369ed
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_frame.h
@@ -0,0 +1,132 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+/*
+ Largest register value that can be coded into
+ the opcode since there are only 6 bits in the
+ register field.
+*/
+#define MAX_6_BIT_VALUE 0x3f
+
+/*
+ This struct holds debug_frame instructions
+*/
+typedef struct Dwarf_P_Frame_Pgm_s *Dwarf_P_Frame_Pgm;
+
+struct Dwarf_P_Frame_Pgm_s {
+ Dwarf_Ubyte dfp_opcode; /* opcode - includes reg # */
+ char *dfp_args; /* operands */
+ int dfp_nbytes; /* number of bytes in args */
+#if 0
+ Dwarf_Unsigned dfp_sym_index; /* 0 unless reloc needed */
+#endif
+ Dwarf_P_Frame_Pgm dfp_next;
+};
+
+
+/*
+ This struct has cie related information. Used to gather data
+ from user program, and later to transform to disk form
+*/
+struct Dwarf_P_Cie_s {
+ Dwarf_Ubyte cie_version;
+ char *cie_aug; /* augmentation */
+ Dwarf_Ubyte cie_code_align; /* alignment of code */
+ Dwarf_Sbyte cie_data_align;
+ Dwarf_Ubyte cie_ret_reg; /* return register # */
+ char *cie_inst; /* initial instruction */
+ long cie_inst_bytes;
+ /* no of init_inst */
+ Dwarf_P_Cie cie_next;
+};
+
+
+/* producer fields */
+struct Dwarf_P_Fde_s {
+ Dwarf_Unsigned fde_unused1;
+
+ /* function/subr die for this fde */
+ Dwarf_P_Die fde_die;
+
+ /* index to asso. cie */
+ Dwarf_Word fde_cie;
+
+ /* Address of first location of the code this frame applies to If
+ fde_end_symbol non-zero, this represents the offset from the
+ symbol indicated by fde_r_symidx */
+ Dwarf_Addr fde_initloc;
+
+ /* Relocation symbol for address of the code this frame applies to.
+ */
+ Dwarf_Unsigned fde_r_symidx;
+
+ /* Bytes of instr for this fde, if known */
+ Dwarf_Unsigned fde_addr_range;
+
+ /* linked list of instructions we will put in fde. */
+ Dwarf_P_Frame_Pgm fde_inst;
+
+ /* number of instructions in fde */
+ long fde_n_inst;
+
+ /* number of bytes of inst in fde */
+ long fde_n_bytes;
+
+ /* offset into exception table for this function. */
+ Dwarf_Signed fde_offset_into_exception_tables;
+
+ /* The symbol for the exception table elf section. */
+ Dwarf_Unsigned fde_exception_table_symbol;
+
+ /* pointer to last inst */
+ Dwarf_P_Frame_Pgm fde_last_inst;
+
+ Dwarf_P_Fde fde_next;
+
+ /* The symbol and offset of the end symbol. When fde_end_symbol is
+ non-zero we must represent the */
+ Dwarf_Addr fde_end_symbol_offset;
+ Dwarf_Unsigned fde_end_symbol;
+
+ int fde_uwordb_size;
+ Dwarf_P_Debug fde_dbg;
+
+ /* If fde_block is non-null, then it is the set of instructions.
+ so we should use it rather than fde_inst. */
+ Dwarf_Unsigned fde_inst_block_size;
+ void *fde_block;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_funcs.c b/usr/src/lib/libdwarf/common/pro_funcs.c
new file mode 100644
index 0000000000..8ff05500bb
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_funcs.c
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another function name to the
+ list of function names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_funcname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *function_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, function_name,
+ dwarf_snk_funcname, error);
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_incl.h b/usr/src/lib/libdwarf/common/pro_incl.h
new file mode 100644
index 0000000000..10bce470c2
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_incl.h
@@ -0,0 +1,92 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#elif defined(HAVE_LIBELF_H)
+/* On one platform without elf.h this gets Elf32_Rel
+ type defined (a required type). */
+#include <libelf.h>
+#endif
+
+#if defined(sun)
+#include <sys/elf_SPARC.h>
+#include <sys/elf_386.h>
+#endif
+
+/* The target address is given: the place in the source integer
+ is to be determined.
+*/
+#ifdef WORDS_BIGENDIAN
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word(dest, \
+ ((char *)source) +srclength-len_out, \
+ len_out) ; \
+ }
+
+
+#else /* LITTLE ENDIAN */
+
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word( (dest) , \
+ ((char *)source) , \
+ len_out) ; \
+ }
+#endif
+
+
+#if defined(sparc) && defined(sun)
+#define REL32 Elf32_Rela
+#define REL64 Elf64_Rela
+#define REL_SEC_PREFIX ".rela"
+#else
+#define REL32 Elf32_Rel
+#define REL64 Elf64_Rel
+#define REL_SEC_PREFIX ".rel"
+#endif
+
+#include "dwarf.h"
+#include "libdwarf.h"
+
+#include "pro_opaque.h"
+#include "pro_error.h"
+#include "pro_util.h"
+#include "pro_encode_nm.h"
+#include "pro_alloc.h"
diff --git a/usr/src/lib/libdwarf/common/pro_init.c b/usr/src/lib/libdwarf/common/pro_init.c
new file mode 100644
index 0000000000..d696113a67
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_init.c
@@ -0,0 +1,261 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_section.h" /* for MAGIC_SECT_NO */
+#include "pro_reloc_symbolic.h"
+#include "pro_reloc_stream.h"
+
+
+static void common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags);
+
+void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len);
+
+/*--------------------------------------------------------------------
+ This function sets up a new dwarf producing region.
+ flags: Indicates type of access method, one of DW_DLC* macros
+ func(): Used to create a new object file, a call back function
+ errhand(): Error Handler provided by user
+ errarg: Argument to errhand()
+ error: returned error value
+--------------------------------------------------------------------*/
+ /* We want the following to have an elf section number that matches
+ 'nothing' */
+static struct Dwarf_P_Section_Data_s init_sect = {
+ MAGIC_SECT_NO, 0, 0, 0, 0
+};
+
+Dwarf_P_Debug
+dwarf_producer_init_b(Dwarf_Unsigned flags,
+ Dwarf_Callback_Func_b func,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Error * error)
+{
+ Dwarf_P_Debug dbg;
+ dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL,
+ sizeof(struct
+ Dwarf_P_Debug_s));
+ if (dbg == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s));
+ /* For the time being */
+ if (func == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ dbg->de_callback_func_b = func;
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ common_init(dbg, flags);
+ return dbg;
+
+}
+
+Dwarf_P_Debug
+dwarf_producer_init(Dwarf_Unsigned flags,
+ Dwarf_Callback_Func func,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Error * error)
+{
+
+ Dwarf_P_Debug dbg;
+
+
+
+ dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL,
+ sizeof(struct
+ Dwarf_P_Debug_s));
+ if (dbg == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s));
+ /* For the time being */
+ if (func == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ dbg->de_callback_func = func;
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ common_init(dbg, flags);
+ return dbg;
+}
+static void
+common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags)
+{
+ unsigned int k;
+
+
+ dbg->de_version_magic_number = PRO_VERSION_MAGIC;
+ dbg->de_n_debug_sect = 0;
+ dbg->de_debug_sects = &init_sect;
+ dbg->de_current_active_section = &init_sect;
+ dbg->de_flags = flags;
+
+ /* Now, with flags set, can use 64bit tests */
+
+
+
+#if defined(HAVE_STRICT_DWARF2_32BIT_OFFSET)
+ /* This is cygnus 32bit offset, as specified in pure dwarf2 v2.0.0.
+ It is consistent with normal DWARF2/3 generation of always
+ generating 32 bit offsets. */
+ dbg->de_64bit_extension = 0;
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_offset_size = (IS_64BIT(dbg) ? 4 : 4);
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ /* non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit
+ pointer environments. */
+ /* Get_REL32_isa here supports 64-bit-pointer dwarf with pure
+ dwarf2 v2.0.0 32bit offsets, as emitted by cygnus tools. And
+ pure 32 bit offset dwarf for 32bit pointer apps. */
+
+ dbg->de_offset_reloc = Get_REL32_isa(dbg);
+#elif defined(HAVE_SGI_IRIX_OFFSETS)
+ /* MIPS-SGI-IRIX 32 or 64, where offsets and lengths are both 64 bit for
+ 64bit pointer objects and both 32 bit for 32bit pointer objects.
+ And a dwarf-reader must check elf info to tell which applies. */
+ dbg->de_64bit_extension = 0;
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_offset_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ dbg->de_offset_reloc = dbg->de_ptr_reloc;
+#else /* HAVE_DWARF2_99_EXTENSION or default. */
+ /* Revised 64 bit output, using distingushed values. Per 1999
+ dwarf3. This allows run-time selection of offset size. */
+ dbg->de_64bit_extension = (IS_64BIT(dbg) ? 1 : 0);
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ if( flags & DW_DLC_OFFSET_SIZE_64 && (dbg->de_pointer_size == 8)) {
+ /* When it's 64 bit address, a 64bit offset is sensible.
+ Arguably a 32 bit address with 64 bit offset could be
+ sensible, but who would want that? */
+ dbg->de_offset_size = 8;
+ dbg->de_64bit_extension = 1;
+ } else {
+ dbg->de_offset_size = 4;
+ dbg->de_64bit_extension = 0;
+ }
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ /* Non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit
+ pointer environments. */
+ /* Get_REL??_isa here supports 64bit-offset dwarf. For 64bit, we
+ emit the extension bytes. */
+
+ dbg->de_offset_reloc = IS_64BIT(dbg) ? Get_REL64_isa(dbg)
+ : Get_REL32_isa(dbg);
+#endif /* HAVE_DWARF2_99_EXTENSION etc. */
+
+ dbg->de_exc_reloc = Get_REL_SEGREL_isa(dbg);
+
+ dbg->de_is_64bit = IS_64BIT(dbg);
+
+
+ if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ dbg->de_relocation_record_size =
+ sizeof(struct Dwarf_Relocation_Data_s);
+ } else {
+
+#if HAVE_ELF64_GETEHDR
+ dbg->de_relocation_record_size =
+ IS_64BIT(dbg)? sizeof(REL64) : sizeof(REL32);
+#else
+ dbg->de_relocation_record_size = sizeof(REL32);
+#endif
+
+ }
+
+ if (dbg->de_offset_size == 8) {
+ dbg->de_ar_data_attribute_form = DW_FORM_data8;
+ dbg->de_ar_ref_attr_form = DW_FORM_ref8;
+ } else {
+ dbg->de_ar_data_attribute_form = DW_FORM_data4;
+ dbg->de_ar_ref_attr_form = DW_FORM_ref4;
+ }
+
+ if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_symbolic;
+ dbg->de_reloc_pair = _dwarf_pro_reloc_length_symbolic;
+ dbg->de_transform_relocs_to_disk =
+ _dwarf_symbolic_relocs_to_disk;
+ } else {
+ if (IS_64BIT(dbg)) {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_stream64;
+ } else {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_stream32;
+ }
+ dbg->de_reloc_pair = 0;
+ dbg->de_transform_relocs_to_disk = _dwarf_stream_relocs_to_disk;
+ }
+ for (k = 0; k < NUM_DEBUG_SECTIONS; ++k) {
+
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[k];
+
+ prel->pr_slots_per_block_to_alloc = DEFAULT_SLOTS_PER_BLOCK;
+ }
+ /* First assume host, target same endianness */
+ dbg->de_same_endian = 1;
+ dbg->de_copy_word = memcpy;
+#ifdef WORDS_BIGENDIAN
+ /* host is big endian, so what endian is target? */
+ if (flags & DW_DLC_TARGET_LITTLEENDIAN) {
+ dbg->de_same_endian = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#else /* little endian */
+ /* host is little endian, so what endian is target? */
+ if (flags & DW_DLC_TARGET_BIGENDIAN) {
+ dbg->de_same_endian = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#endif /* !WORDS_BIGENDIAN */
+
+
+ return;
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_line.c b/usr/src/lib/libdwarf/common/pro_line.c
new file mode 100644
index 0000000000..69d3e339f0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_line.c
@@ -0,0 +1,300 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include "pro_incl.h"
+#include "pro_line.h"
+
+Dwarf_Unsigned _dwarf_pro_add_line_entry(Dwarf_P_Debug,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin,
+ Dwarf_Ubyte opc,
+ Dwarf_Error * error);
+
+/*-------------------------------------------------------------------------
+ Add a entry to the line information section
+ file_index: index of file in file entries, obtained from
+ add_file_entry() call.
+
+ This function actually calls _dwarf_pro_add_line_entry(), with
+ an extra parameter, the opcode. Done so that interface calls
+ dwarf_lne_set_address() and dwarf_lne_end_sequence() can use
+ this internal routine.
+---------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_line_entry(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin, Dwarf_Error * error)
+{
+ Dwarf_Unsigned retval;
+
+ retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address, 0,
+ line_no, col_no, is_stmt_begin,
+ is_bb_begin, 0, error);
+ return retval;
+}
+
+/*------------------------------------------------------------------------
+ Ask to emit DW_LNE_set_address opcode explicitly. Used by be
+ to emit start of a new .text section, or to force a relocated
+ address into debug line information entry.
+-------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_lne_set_address(Dwarf_P_Debug dbg,
+ Dwarf_Addr offs,
+ Dwarf_Unsigned symidx, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc;
+ Dwarf_Unsigned retval;
+
+ opc = DW_LNE_set_address;
+ retval =
+ _dwarf_pro_add_line_entry(dbg, 0, offs, symidx, 0, 0, 0, 0, opc,
+ error);
+ return retval;
+}
+
+/*------------------------------------------------------------------------
+ Ask to emit end_seqence opcode. Used normally at the end of a
+ compilation unit. Can also be used in the middle if there
+ are gaps in the region described by the code address.
+-------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_lne_end_sequence(Dwarf_P_Debug dbg,
+ Dwarf_Addr end_address, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc;
+ Dwarf_Unsigned retval;
+
+ opc = DW_LNE_end_sequence;
+ retval =
+ _dwarf_pro_add_line_entry(dbg, 0, end_address, 0, 0, 0, 0, 0,
+ opc, error);
+ return retval;
+}
+
+/*----------------------------------------------------------------------------
+ Add an entry in the internal list of lines mantained by producer.
+ Opc indicates if an opcode needs to be generated, rather than just
+ an entry in the matrix. During opcodes generation time, these
+ opcodes will be used.
+-----------------------------------------------------------------------------*/
+Dwarf_Unsigned
+_dwarf_pro_add_line_entry(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin,
+ Dwarf_Ubyte opc, Dwarf_Error * error)
+{
+ if (dbg->de_lines == NULL) {
+ dbg->de_lines = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (dbg->de_lines == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_line = dbg->de_lines;
+ _dwarf_pro_reg_init(dbg->de_lines);
+
+ } else {
+ dbg->de_last_line->dpl_next = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (dbg->de_last_line->dpl_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_line = dbg->de_last_line->dpl_next;
+ _dwarf_pro_reg_init(dbg->de_last_line);
+ }
+ dbg->de_last_line->dpl_address = code_address;
+ dbg->de_last_line->dpl_file = (unsigned long) file_index;
+ dbg->de_last_line->dpl_line = (unsigned long) line_no;
+ dbg->de_last_line->dpl_column = (unsigned long) col_no;
+ dbg->de_last_line->dpl_is_stmt = is_stmt_begin;
+ dbg->de_last_line->dpl_basic_block = is_bb_begin;
+ dbg->de_last_line->dpl_opc = opc;
+ dbg->de_last_line->dpl_r_symidx = symidx;
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ Add a directory declaration to the debug_line section. Stored
+ in linked list.
+------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_directory_decl(Dwarf_P_Debug dbg,
+ char *name, Dwarf_Error * error)
+{
+ if (dbg->de_inc_dirs == NULL) {
+ dbg->de_inc_dirs = (Dwarf_P_Inc_Dir)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s));
+ if (dbg->de_inc_dirs == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_inc_dir = dbg->de_inc_dirs;
+ dbg->de_n_inc_dirs = 1;
+ } else {
+ dbg->de_last_inc_dir->did_next = (Dwarf_P_Inc_Dir)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s));
+ if (dbg->de_last_inc_dir->did_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_inc_dir = dbg->de_last_inc_dir->did_next;
+ dbg->de_n_inc_dirs++;
+ }
+ dbg->de_last_inc_dir->did_name =
+ (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
+ if (dbg->de_last_inc_dir->did_name == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_STRING_ALLOC, DW_DLV_NOCOUNT);
+ }
+ strcpy(dbg->de_last_inc_dir->did_name, name);
+ dbg->de_last_inc_dir->did_next = NULL;
+
+ return dbg->de_n_inc_dirs;
+}
+
+/*-----------------------------------------------------------------------
+ Add a file entry declaration to the debug_line section. Stored
+ in linked list. The data is immediately encodes as leb128
+ and stored in Dwarf_P_F_Entry_s struct.
+------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_file_decl(Dwarf_P_Debug dbg,
+ char *name,
+ Dwarf_Unsigned dir_idx,
+ Dwarf_Unsigned time_mod,
+ Dwarf_Unsigned length, Dwarf_Error * error)
+{
+ Dwarf_P_F_Entry cur;
+ char *ptr;
+ int nbytes_idx, nbytes_time, nbytes_len;
+ char buffidx[ENCODE_SPACE_NEEDED];
+ char bufftime[ENCODE_SPACE_NEEDED];
+ char bufflen[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (dbg->de_file_entries == NULL) {
+ dbg->de_file_entries = (Dwarf_P_F_Entry)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
+ if (dbg->de_file_entries == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
+ DW_DLV_NOCOUNT);
+ }
+ cur = dbg->de_file_entries;
+ dbg->de_last_file_entry = cur;
+ dbg->de_n_file_entries = 1;
+ } else {
+ cur = dbg->de_last_file_entry;
+ cur->dfe_next = (Dwarf_P_F_Entry)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
+ if (cur->dfe_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
+ DW_DLV_NOCOUNT);
+ }
+ cur = cur->dfe_next;
+ dbg->de_last_file_entry = cur;
+ dbg->de_n_file_entries++;
+ }
+ cur->dfe_name = (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
+ if (cur->dfe_name == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ strcpy((char *) cur->dfe_name, name);
+ res = _dwarf_pro_encode_leb128_nm(dir_idx, &nbytes_idx,
+ buffidx, sizeof(buffidx));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ res = _dwarf_pro_encode_leb128_nm(time_mod, &nbytes_time,
+ bufftime, sizeof(bufftime));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ res = _dwarf_pro_encode_leb128_nm(length, &nbytes_len,
+ bufflen, sizeof(bufflen));
+ cur->dfe_args = (char *)
+ _dwarf_p_get_alloc(dbg, nbytes_idx + nbytes_time + nbytes_len);
+ if (cur->dfe_args == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ ptr = cur->dfe_args;
+ memcpy((void *) ptr, buffidx, nbytes_idx);
+ ptr += nbytes_idx;
+ memcpy((void *) ptr, bufftime, nbytes_time);
+ ptr += nbytes_time;
+ memcpy((void *) ptr, bufflen, nbytes_len);
+ ptr += nbytes_len;
+ cur->dfe_nbytes = nbytes_idx + nbytes_time + nbytes_len;
+ cur->dfe_next = NULL;
+
+ return dbg->de_n_file_entries;
+}
+
+
+/*---------------------------------------------------------------------
+ Initialize a row of the matrix for line numbers, meaning
+ initialize the struct corresponding to it
+----------------------------------------------------------------------*/
+void
+_dwarf_pro_reg_init(Dwarf_P_Line cur_line)
+{
+ cur_line->dpl_address = 0;
+ cur_line->dpl_file = 1;
+ cur_line->dpl_line = 1;
+ cur_line->dpl_column = 0;
+ cur_line->dpl_is_stmt = DEFAULT_IS_STMT;
+ cur_line->dpl_basic_block = false;
+ cur_line->dpl_next = NULL;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_line.h b/usr/src/lib/libdwarf/common/pro_line.h
new file mode 100644
index 0000000000..eed941239d
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_line.h
@@ -0,0 +1,116 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#define VERSION 2
+#ifdef __i386
+#define MIN_INST_LENGTH 1
+#else
+#define MIN_INST_LENGTH 4
+#endif
+#define DEFAULT_IS_STMT false
+ /* line base and range are temporarily defines.
+ They need to be calculated later */
+#define LINE_BASE -1
+#define LINE_RANGE 4
+
+#define OPCODE_BASE 10
+#define MAX_OPCODE 255
+
+
+/*
+ This struct is used to hold entries in the include directories
+ part of statement prologue.
+*/
+struct Dwarf_P_Inc_Dir_s {
+ char *did_name; /* name of directory */
+ Dwarf_P_Inc_Dir did_next;
+};
+
+
+/*
+ This struct holds file entries for the statement prologue.
+ Defined in pro_line.h
+*/
+struct Dwarf_P_F_Entry_s {
+ char *dfe_name;
+ char *dfe_args; /* has dir index, time of modification,
+ length in bytes. Encodes as leb128 */
+ int dfe_nbytes; /* number of bytes in args */
+ Dwarf_P_F_Entry dfe_next;
+};
+
+
+/*
+ Struct holding line number information for each of the producer
+ line entries
+*/
+struct Dwarf_P_Line_s {
+ /* code address */
+ Dwarf_Addr dpl_address;
+
+ /* file index, index into file entry */
+ Dwarf_Word dpl_file;
+
+ /* line number */
+ Dwarf_Word dpl_line;
+
+ /* column number */
+ Dwarf_Word dpl_column;
+
+ /* whether its a beginning of a stmt */
+ Dwarf_Ubyte dpl_is_stmt;
+
+ /* whether its a beginning of basic blk */
+ Dwarf_Ubyte dpl_basic_block;
+
+ /* used to store opcodes set_address, and end_seq */
+ Dwarf_Ubyte dpl_opc;
+
+ /*
+ Used only for relocations. Has index of symbol relative to
+ which relocation has to be done (the S part in S + A) */
+ Dwarf_Unsigned dpl_r_symidx;
+
+ Dwarf_P_Line dpl_next;
+};
+
+/*
+ to initialize state machine registers, definition in
+ pro_line.c
+*/
+void _dwarf_pro_reg_init(Dwarf_P_Line);
diff --git a/usr/src/lib/libdwarf/common/pro_macinfo.c b/usr/src/lib/libdwarf/common/pro_macinfo.c
new file mode 100644
index 0000000000..cfa820aee6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_macinfo.c
@@ -0,0 +1,472 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_macinfo.h"
+
+/*
+ I don't much like the error strings this generates, since
+ like the rest of libdwarf they are simple strings with
+ no useful numbers in them. But that's not something I can
+ fix without more work than I have time for
+ right now. davea Nov 94.
+*/
+
+/* these are gross overestimates of the number of
+** bytes needed to store a number in LEB form.
+** Just estimates, and since blocks are reasonable size,
+** the end-block waste is small.
+** Of course the waste is NOT present on disk.
+*/
+
+#define COMMAND_LEN ENCODE_SPACE_NEEDED
+#define LINE_LEN ENCODE_SPACE_NEEDED
+#define BASE_MACINFO_MALLOC_LEN 2048
+
+static int
+libdwarf_compose_begin(Dwarf_P_Debug dbg, int code,
+ size_t maxlen, int *compose_error_type)
+{
+ unsigned char *nextchar;
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+
+ if (curblk == 0) {
+ struct dw_macinfo_block_s *newb;
+ size_t len;
+
+ /* initial allocation */
+ size_t blen = BASE_MACINFO_MALLOC_LEN;
+
+ if (blen < maxlen) {
+ blen = 2 * maxlen;
+ }
+ len = sizeof(struct dw_macinfo_block_s) + blen;
+ newb =
+ (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len);
+ if (!newb) {
+ *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ newb->mb_data =
+ (char *) newb + sizeof(struct dw_macinfo_block_s);
+ newb->mb_avail_len = blen;
+ newb->mb_used_len = 0;
+ newb->mb_macinfo_data_space_len = blen;
+ dbg->de_first_macinfo = newb;
+ dbg->de_current_macinfo = newb;
+ curblk = newb;
+ } else if (curblk->mb_avail_len < maxlen) {
+ struct dw_macinfo_block_s *newb;
+ size_t len;
+
+ /* no space left in block: allocate a new block */
+ size_t blen =
+ dbg->de_current_macinfo->mb_macinfo_data_space_len * 2;
+ if (blen < maxlen) {
+ blen = 2 * maxlen;
+ }
+ len = sizeof(struct dw_macinfo_block_s) + blen;
+ newb =
+ (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len);
+ if (!newb) {
+ *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ newb->mb_data =
+ (char *) newb + sizeof(struct dw_macinfo_block_s);
+ newb->mb_avail_len = blen;
+ newb->mb_used_len = 0;
+ newb->mb_macinfo_data_space_len = blen;
+ dbg->de_first_macinfo->mb_next = newb;
+ dbg->de_current_macinfo = newb;
+ curblk = newb;
+ }
+ /* now curblk has enough room */
+ dbg->de_compose_avail = curblk->mb_avail_len;
+ dbg->de_compose_used_len = curblk->mb_used_len;
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+ *nextchar = code;
+ dbg->de_compose_avail--;
+ ++dbg->de_compose_used_len;
+ return DW_DLV_OK;
+}
+
+
+
+static void
+libdwarf_compose_add_string(Dwarf_P_Debug dbg, char *string, size_t len)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+ unsigned char *nextchar;
+
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+
+ len += 1; /* count the null terminator */
+
+ memcpy(nextchar, string, len);
+ dbg->de_compose_avail -= len;
+ dbg->de_compose_used_len += len;
+ return;
+
+}
+static int
+libdwarf_compose_add_line(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line, int *compose_error_type)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+ unsigned char *nextchar;
+ int res;
+ int nbytes;
+
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+
+ /* Put the created leb number directly into the macro buffer If
+ dbg->de_compose_avail is > INT_MAX this will not work as the
+ 'int' will look negative to _dwarf_pro_encode_leb128_nm! */
+
+ res = _dwarf_pro_encode_leb128_nm(line, &nbytes,
+ (char *) nextchar,
+ (int) dbg->de_compose_avail);
+ if (res != DW_DLV_OK) {
+ *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE;
+ return DW_DLV_ERROR;
+ }
+
+ dbg->de_compose_avail -= nbytes;
+ dbg->de_compose_used_len += nbytes;
+ return DW_DLV_OK;
+}
+
+/*
+ This function actually 'commits' the space used by the
+ preceeding calls.
+*/
+static int
+libdwarf_compose_complete(Dwarf_P_Debug dbg, int *compose_error_type)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+
+ if (dbg->de_compose_used_len > curblk->mb_macinfo_data_space_len) {
+ *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE;
+ return DW_DLV_ERROR;
+ }
+ curblk->mb_avail_len = dbg->de_compose_avail;
+ curblk->mb_used_len = dbg->de_compose_used_len;
+ return DW_DLV_OK;
+}
+
+
+
+int
+dwarf_def_macro(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line,
+ char *macname, char *macvalue, Dwarf_Error * error)
+{
+ size_t len;
+ size_t len2;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (macname == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(macname) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ if (macvalue) {
+ len2 = strlen(macvalue) + 1;
+ } else {
+ len2 = 0;
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len + len2 + 1; /* 1
+ for
+ space
+ character
+ we
+ add */
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_define, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, line, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, macname, len);
+ libdwarf_compose_add_string(dbg, " ", 1);
+ if (macvalue) {
+ libdwarf_compose_add_string(dbg, " ", 1);
+ libdwarf_compose_add_string(dbg, macvalue, len2);
+ }
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_undef_macro(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line,
+ char *macname, Dwarf_Error * error)
+{
+
+ size_t len;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (macname == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(macname) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_undef, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, line, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, macname, len);
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_start_macro_file(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned fileindex,
+ Dwarf_Unsigned linenumber, Dwarf_Error * error)
+{
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + LINE_LEN;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_start_file, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, fileindex,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, linenumber,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_end_macro_file(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_end_file, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_vendor_ext(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned constant,
+ char *string, Dwarf_Error * error)
+{
+ size_t len;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (string == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(string) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_vendor_ext, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, constant, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, string, len);
+ libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+
+
+int
+_dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error)
+{
+ /* Total num of bytes in .debug_macinfo section. */
+ Dwarf_Unsigned mac_num_bytes;
+
+ /* Points to first byte of .debug_macinfo buffer. */
+ Dwarf_Small *macinfo;
+
+ /* Fills in the .debug_macinfo buffer. */
+ Dwarf_Small *macinfo_ptr;
+
+
+ /* Used to scan the section data buffers. */
+ struct dw_macinfo_block_s *m_prev;
+ struct dw_macinfo_block_s *m_sect;
+
+
+ /* Get the size of the debug_macinfo data */
+ mac_num_bytes = 0;
+ for (m_sect = dbg->de_first_macinfo; m_sect != NULL;
+ m_sect = m_sect->mb_next) {
+ mac_num_bytes += m_sect->mb_used_len;
+ }
+ /* Tthe final entry has a type code of 0 to indicate It is final
+ for this CU Takes just 1 byte. */
+ mac_num_bytes += 1;
+
+ GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_MACINFO],
+ macinfo, (unsigned long) mac_num_bytes, error);
+ if (macinfo == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ macinfo_ptr = macinfo;
+ m_prev = 0;
+ for (m_sect = dbg->de_first_macinfo; m_sect != NULL;
+ m_sect = m_sect->mb_next) {
+ memcpy(macinfo_ptr, m_sect->mb_data, m_sect->mb_used_len);
+ macinfo_ptr += m_sect->mb_used_len;
+ if (m_prev) {
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev);
+ m_prev = 0;
+ }
+ m_prev = m_sect;
+ }
+ *macinfo_ptr = 0; /* the type code of 0 as last entry */
+ if (m_prev) {
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev);
+ m_prev = 0;
+ }
+
+ dbg->de_first_macinfo = NULL;
+ dbg->de_current_macinfo = NULL;
+
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_macinfo.h b/usr/src/lib/libdwarf/common/pro_macinfo.h
new file mode 100644
index 0000000000..852a0cec1f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_macinfo.h
@@ -0,0 +1,40 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+int _dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_opaque.h b/usr/src/lib/libdwarf/common/pro_opaque.h
new file mode 100644
index 0000000000..befc69faa6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_opaque.h
@@ -0,0 +1,484 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+#include <stddef.h>
+
+/*
+ Sgidefs included to define __uint32_t,
+ a guaranteed 4-byte quantity.
+*/
+#include "libdwarfdefs.h"
+
+#define true 1
+#define false 0
+
+/* to identify a cie */
+#define DW_CIE_ID ~(0x0)
+#define DW_CIE_VERSION 1
+
+/*Dwarf_Word is unsigned word usable for index, count in memory */
+/*Dwarf_Sword is signed word usable for index, count in memory */
+/* The are 32 or 64 bits depending if 64 bit longs or not, which
+** fits the ILP32 and LP64 models
+** These work equally well with ILP64.
+*/
+
+typedef unsigned long Dwarf_Word;
+typedef long Dwarf_Sword;
+
+
+typedef signed char Dwarf_Sbyte;
+typedef unsigned char Dwarf_Ubyte;
+typedef signed short Dwarf_Shalf;
+
+/*
+ On any change that makes libdwarf producer
+ incompatible, increment this number.
+ 1->2->3 ...
+
+*/
+#define PRO_VERSION_MAGIC 0xdead1
+
+
+/* these 2 are fixed sizes which must not vary with the
+** ILP32/LP64 model. These two stay at 32 bit.
+*/
+typedef __uint32_t Dwarf_ufixed;
+typedef __int32_t Dwarf_sfixed;
+
+/*
+ producer:
+ This struct is used to hold information about all
+ debug* sections. On creating a new section, section
+ names and indices are added to this struct
+ definition in pro_section.h
+*/
+typedef struct Dwarf_P_Section_Data_s *Dwarf_P_Section_Data;
+
+/*
+ producer:
+ This struct is used to hold entries in the include directories
+ part of statement prologue. Definition in pro_line.h
+*/
+typedef struct Dwarf_P_Inc_Dir_s *Dwarf_P_Inc_Dir;
+
+/*
+ producer:
+ This struct holds file entries for the statement prologue.
+ Defined in pro_line.h
+*/
+typedef struct Dwarf_P_F_Entry_s *Dwarf_P_F_Entry;
+
+/*
+ producer:
+ This struct holds information for each cie. Defn in pro_frame.h
+*/
+typedef struct Dwarf_P_Cie_s *Dwarf_P_Cie;
+
+/*
+ producer:
+ Struct to hold line number information, different from
+ Dwarf_Line opaque type.
+*/
+typedef struct Dwarf_P_Line_s *Dwarf_P_Line;
+
+/*
+ producer:
+ Struct to hold information about address ranges.
+*/
+typedef struct Dwarf_P_Simple_nameentry_s *Dwarf_P_Simple_nameentry;
+typedef struct Dwarf_P_Simple_name_header_s *Dwarf_P_Simple_name_header;
+typedef struct Dwarf_P_Arange_s *Dwarf_P_Arange;
+typedef struct Dwarf_P_Per_Reloc_Sect_s *Dwarf_P_Per_Reloc_Sect;
+typedef struct Dwarf_P_Per_Sect_String_Attrs_s *Dwarf_P_Per_Sect_String_Attrs;
+
+/* Defined to get at the elf section numbers and section name
+ indices in symtab for the dwarf sections
+ Must match .rel.* names in _dwarf_rel_section_names
+ exactly.
+*/
+#define DEBUG_INFO 0
+#define DEBUG_LINE 1
+#define DEBUG_ABBREV 2
+#define DEBUG_FRAME 3
+#define DEBUG_ARANGES 4
+#define DEBUG_PUBNAMES 5
+#define DEBUG_STR 6
+#define DEBUG_FUNCNAMES 7
+#define DEBUG_TYPENAMES 8
+#define DEBUG_VARNAMES 9
+#define DEBUG_WEAKNAMES 10
+#define DEBUG_MACINFO 11
+#define DEBUG_LOC 12
+
+ /* number of debug_* sections not including the relocations */
+#define NUM_DEBUG_SECTIONS DEBUG_LOC + 1
+
+
+struct Dwarf_P_Die_s {
+ Dwarf_Unsigned di_offset; /* offset in debug info */
+ char *di_abbrev; /* abbreviation */
+ Dwarf_Word di_abbrev_nbytes; /* # of bytes in abbrev */
+ Dwarf_Tag di_tag;
+ Dwarf_P_Die di_parent; /* parent of current die */
+ Dwarf_P_Die di_child; /* first child */
+ /* The last child field makes linking up children an O(1) operation,
+ See pro_die.c. */
+ Dwarf_P_Die di_last_child;
+ Dwarf_P_Die di_left; /* left sibling */
+ Dwarf_P_Die di_right; /* right sibling */
+ Dwarf_P_Attribute di_attrs; /* list of attributes */
+ Dwarf_P_Attribute di_last_attr; /* last attribute */
+ int di_n_attr; /* number of attributes */
+ Dwarf_P_Debug di_dbg; /* For memory management */
+ Dwarf_Unsigned di_marker; /* used to attach symbols to dies */
+};
+
+
+/* producer fields */
+struct Dwarf_P_Attribute_s {
+ Dwarf_Half ar_attribute; /* Attribute Value. */
+ Dwarf_Half ar_attribute_form; /* Attribute Form. */
+ Dwarf_P_Die ar_ref_die; /* die pointer if form ref */
+ char *ar_data; /* data, format given by form */
+ Dwarf_Unsigned ar_nbytes; /* no. of bytes of data */
+ Dwarf_Unsigned ar_rel_symidx; /* when attribute has a
+ relocatable value, holds
+ index of symbol in SYMTAB */
+ Dwarf_Ubyte ar_rel_type; /* relocation type */
+ Dwarf_Word ar_rel_offset; /* Offset of relocation within block */
+ char ar_reloc_len; /* Number of bytes that relocation
+ applies to. 4 or 8. Unused and may
+ be 0 if if ar_rel_type is
+ R_MIPS_NONE */
+ Dwarf_P_Attribute ar_next;
+};
+
+/* A block of .debug_macinfo data: this forms a series of blocks.
+** Each macinfo input is compressed immediately and put into
+** the current block if room, else a newblock allocated.
+** The space allocation is such that the block and the macinfo
+** data are one malloc block: free with a pointer to this and the
+** mb_data is freed automatically.
+** Like the struct hack, but legal ANSI C.
+*/
+struct dw_macinfo_block_s {
+ struct dw_macinfo_block_s *mb_next;
+ unsigned long mb_avail_len;
+ unsigned long mb_used_len;
+ unsigned long mb_macinfo_data_space_len;
+ char *mb_data; /* original malloc ptr. */
+};
+
+/* dwarf_sn_kind is for the array of similarly-treated
+ name -> cu ties
+*/
+enum dwarf_sn_kind { dwarf_snk_pubname, dwarf_snk_funcname,
+ dwarf_snk_weakname, dwarf_snk_typename,
+ dwarf_snk_varname,
+ dwarf_snk_entrycount /* this one must be last */
+};
+
+
+
+/* The calls to add a varname etc use a list of
+ these as the list.
+*/
+struct Dwarf_P_Simple_nameentry_s {
+ Dwarf_P_Die sne_die;
+ char *sne_name;
+ int sne_name_len;
+ Dwarf_P_Simple_nameentry sne_next;
+};
+
+/* An array of these, each of which heads a list
+ of Dwarf_P_Simple_nameentry
+*/
+struct Dwarf_P_Simple_name_header_s {
+ Dwarf_P_Simple_nameentry sn_head;
+ Dwarf_P_Simple_nameentry sn_tail;
+ Dwarf_Signed sn_count;
+
+ /* length that will be generated, not counting fixed header or
+ trailer */
+ Dwarf_Signed sn_net_len;
+};
+typedef int (*_dwarf_pro_reloc_name_func_ptr) (Dwarf_P_Debug dbg,
+ int sec_index,
+ Dwarf_Unsigned offset,/* r_offset */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length);
+
+typedef int (*_dwarf_pro_reloc_length_func_ptr) (Dwarf_P_Debug dbg,
+ int sec_index, Dwarf_Unsigned offset,/* r_offset */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length);
+typedef int (*_dwarf_pro_transform_relocs_func_ptr) (Dwarf_P_Debug dbg,
+ Dwarf_Signed *
+ new_sec_count);
+
+/*
+ Each slot in a block of slots could be:
+ a binary stream relocation entry (32 or 64bit relocation data)
+ a SYMBOLIC relocation entry.
+ During creation sometimes we create multiple chained blocks,
+ but sometimes we create a single long block.
+ Before returning reloc data to caller,
+ we switch to a single, long-enough,
+ block.
+
+ We make counters here Dwarf_Unsigned so that we
+ get sufficient alignment. Since we use space after
+ the struct (at malloc time) for user data which
+ must have Dwarf_Unsigned alignment, this
+ struct must have that alignment too.
+*/
+struct Dwarf_P_Relocation_Block_s {
+ Dwarf_Unsigned rb_slots_in_block; /* slots in block, as created */
+ Dwarf_Unsigned rb_next_slot_to_use; /* counter, start at 0. */
+ struct Dwarf_P_Relocation_Block_s *rb_next;
+ char *rb_where_to_add_next; /* pointer to next slot (might be past
+ end, depending on
+ rb_next_slot_to_use) */
+ char *rb_data; /* data area */
+};
+
+/* One of these per potential relocation section
+ So one per actual dwarf section.
+ Left zeroed when not used (some sections have
+ no relocations).
+*/
+struct Dwarf_P_Per_Reloc_Sect_s {
+ unsigned long pr_reloc_total_count; /* total number of entries
+ across all blocks */
+
+ unsigned long pr_slots_per_block_to_alloc; /* at Block alloc, this
+ is the default number of slots to use */
+
+ int pr_sect_num_of_reloc_sect; /* sect number returned by
+ de_callback_func() or de_callback_func_b() call, this is the sect
+ number of the relocation section. */
+
+ /* singly-linked list. add at and ('last') with count of blocks */
+ struct Dwarf_P_Relocation_Block_s *pr_first_block;
+ struct Dwarf_P_Relocation_Block_s *pr_last_block;
+ unsigned long pr_block_count;
+};
+
+#define DEFAULT_SLOTS_PER_BLOCK 3
+
+typedef struct memory_list_s {
+ struct memory_list_s *prev;
+ struct memory_list_s *next;
+} memory_list_t;
+
+struct Dwarf_P_Per_Sect_String_Attrs_s {
+ int sect_sa_section_number;
+ unsigned sect_sa_n_alloc;
+ unsigned sect_sa_n_used;
+ Dwarf_P_String_Attr sect_sa_list;
+};
+
+/* Fields used by producer */
+struct Dwarf_P_Debug_s {
+ /* used to catch dso passing dbg to another DSO with incompatible
+ version of libdwarf See PRO_VERSION_MAGIC */
+ int de_version_magic_number;
+
+ Dwarf_Handler de_errhand;
+ Dwarf_Ptr de_errarg;
+
+ /* Call back function, used to create .debug* sections. Provided
+ by user. Only of these used per dbg. */
+ Dwarf_Callback_Func de_callback_func;
+ Dwarf_Callback_Func_b de_callback_func_b;
+
+ /* Flags from producer_init call */
+ Dwarf_Unsigned de_flags;
+
+ /* This holds information on debug section stream output, including
+ the stream data */
+ Dwarf_P_Section_Data de_debug_sects;
+
+ /* Pointer to the 'current active' section */
+ Dwarf_P_Section_Data de_current_active_section;
+
+ /* Number of debug data streams globs. */
+ Dwarf_Word de_n_debug_sect;
+
+ /* File entry information, null terminated singly-linked list */
+ Dwarf_P_F_Entry de_file_entries;
+ Dwarf_P_F_Entry de_last_file_entry;
+ Dwarf_Unsigned de_n_file_entries;
+
+ /* Has the directories used to search for source files */
+ Dwarf_P_Inc_Dir de_inc_dirs;
+ Dwarf_P_Inc_Dir de_last_inc_dir;
+ Dwarf_Unsigned de_n_inc_dirs;
+
+ /* Has all the line number info for the stmt program */
+ Dwarf_P_Line de_lines;
+ Dwarf_P_Line de_last_line;
+
+ /* List of cie's for the debug unit */
+ Dwarf_P_Cie de_frame_cies;
+ Dwarf_P_Cie de_last_cie;
+ Dwarf_Unsigned de_n_cie;
+
+ /* Singly-linked list of fde's for the debug unit */
+ Dwarf_P_Fde de_frame_fdes;
+ Dwarf_P_Fde de_last_fde;
+ Dwarf_Unsigned de_n_fde;
+
+ /* First die, leads to all others */
+ Dwarf_P_Die de_dies;
+
+ /* Pointer to list of strings */
+ char *de_strings;
+
+ /* Pointer to chain of aranges */
+ Dwarf_P_Arange de_arange;
+ Dwarf_P_Arange de_last_arange;
+ Dwarf_Sword de_arange_count;
+
+ /* macinfo controls. */
+ /* first points to beginning of the list during creation */
+ struct dw_macinfo_block_s *de_first_macinfo;
+
+ /* current points to the current, unfilled, block */
+ struct dw_macinfo_block_s *de_current_macinfo;
+
+ /* Pointer to the first section, to support reset_section_bytes */
+ Dwarf_P_Section_Data de_first_debug_sect;
+
+ /* handles pubnames, weaknames, etc. See dwarf_sn_kind in
+ pro_opaque.h */
+ struct Dwarf_P_Simple_name_header_s
+ de_simple_name_headers[dwarf_snk_entrycount];
+
+ /* relocation data. not all sections will actally have relocation
+ info, of course */
+ struct Dwarf_P_Per_Reloc_Sect_s de_reloc_sect[NUM_DEBUG_SECTIONS];
+ int de_reloc_next_to_return; /* iterator on reloc sections
+ (SYMBOLIC output) */
+
+ /* used in remembering sections */
+ int de_elf_sects[NUM_DEBUG_SECTIONS]; /* elf sect number of
+ the section itself, DEBUG_LINE for example */
+
+ Dwarf_Unsigned de_sect_name_idx[NUM_DEBUG_SECTIONS]; /* section
+ name index or handle for the name of the symbol for
+ DEBUG_LINE for example */
+
+ int de_offset_reloc; /* offset reloc type, R_MIPS_32 for
+ example. Specific to the ABI being
+ produced. Relocates offset size
+ field */
+ int de_exc_reloc; /* reloc type specific to exception
+ table relocs. */
+ int de_ptr_reloc; /* standard reloc type, R_MIPS_32 for
+ example. Specific to the ABI being
+ produced. relocates pointer size
+ field */
+
+ unsigned char de_offset_size; /* section offset. Here to
+ avoid test of abi in macro
+ at run time MIPS -n32 4,
+ -64 8. */
+
+ unsigned char de_pointer_size; /* size of pointer in target.
+ Here to avoid test of abi in
+ macro at run time MIPS -n32
+ 4, -64 is 8. */
+
+ unsigned char de_is_64bit; /* non-zero if is 64bit. Else 32 bit:
+ used for passing this info as a flag
+ */
+ unsigned char de_relocation_record_size; /* reloc record size
+ varies by ABI and
+ relocation-output
+ method (stream or
+ symbolic) */
+
+ unsigned char de_64bit_extension; /* non-zero if creating 64 bit
+ offsets using dwarf2-99
+ extension proposal */
+
+ int de_ar_data_attribute_form; /* data8, data4 abi dependent */
+ int de_ar_ref_attr_form; /* ref8 ref4 , abi dependent */
+
+ /* simple name relocations */
+ _dwarf_pro_reloc_name_func_ptr de_reloc_name;
+
+ /* relocations for a length, requiring a pair of symbols */
+ _dwarf_pro_reloc_length_func_ptr de_reloc_pair;
+
+ _dwarf_pro_transform_relocs_func_ptr de_transform_relocs_to_disk;
+
+ /* following used for macro buffers */
+ unsigned long de_compose_avail;
+ unsigned long de_compose_used_len;
+
+ unsigned char de_same_endian;
+ void *(*de_copy_word) (void *, const void *, size_t);
+
+ /* Add new fields at the END of this struct to preserve some hope
+ of sensible behavior on dbg passing between DSOs linked with
+ mismatched libdwarf producer versions. */
+
+ Dwarf_P_Marker de_markers; /* pointer to array of markers */
+ unsigned de_marker_n_alloc;
+ unsigned de_marker_n_used;
+ int de_sect_sa_next_to_return; /* Iterator on sring attrib sects */
+ /* String attributes data of each section. */
+ struct Dwarf_P_Per_Sect_String_Attrs_s de_sect_string_attr[NUM_DEBUG_SECTIONS];
+};
+
+#define CURRENT_VERSION_STAMP 2
+
+Dwarf_Unsigned _dwarf_add_simple_name_entry(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *entry_name,
+ enum dwarf_sn_kind
+ entrykind,
+ Dwarf_Error * error);
+
+
+#define DISTINGUISHED_VALUE 0xffffffff /* 64bit extension flag */
diff --git a/usr/src/lib/libdwarf/common/pro_pubnames.c b/usr/src/lib/libdwarf/common/pro_pubnames.c
new file mode 100644
index 0000000000..e07fe35943
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_pubnames.c
@@ -0,0 +1,63 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+
+/*
+ This function adds another public name to the
+ list of public names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+
+Dwarf_Unsigned
+dwarf_add_pubname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *pubname_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, pubname_name,
+ dwarf_snk_pubname, error);
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc.c b/usr/src/lib/libdwarf/common/pro_reloc.c
new file mode 100644
index 0000000000..66f16acbd0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc.c
@@ -0,0 +1,269 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+/*#include <elfaccess.h> */
+#include "pro_incl.h"
+
+
+/*Do initial alloc of newslots slots.
+ Fails only if malloc fails.
+
+ Supposed to be called before any relocs allocated.
+ Ignored if after any allocated.
+
+ Part of an optimization, so that for a known 'newslots'
+ relocations count we can preallocate the right size block.
+ Called from just 2 places.
+
+ returns DW_DLV_OK or DW_DLV_ERROR
+*/
+int
+_dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg,
+ int rel_sec_index,
+ Dwarf_Unsigned newslots)
+{
+ unsigned long len = 0;
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index];
+ unsigned long slots_in_blk = (unsigned long) newslots;
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ if (prel->pr_first_block)
+ return DW_DLV_OK; /* do nothing */
+
+ len = sizeof(struct Dwarf_P_Relocation_Block_s) +
+ slots_in_blk * rel_rec_size;
+
+
+ data = (struct Dwarf_P_Relocation_Block_s *)
+ _dwarf_p_get_alloc(dbg, len);
+ if (!data) {
+ return DW_DLV_ERROR;
+ }
+ data->rb_slots_in_block = slots_in_blk; /* could use default
+ here, as fallback in
+ case our origininal
+ estimate wrong. When
+ we call this we
+ presumably know what
+ we are doing, so
+ keep this count for
+ now */
+ data->rb_next_slot_to_use = 0;
+ data->rb_where_to_add_next =
+ ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
+ data->rb_data = data->rb_where_to_add_next;
+
+ prel->pr_first_block = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count = 1;
+
+
+ return DW_DLV_OK;
+}
+
+
+/*Do alloc of slots.
+ Fails only if malloc fails.
+
+ Only allocator used.
+
+ returns DW_DLV_OK or DW_DLV_ERROR
+*/
+int
+_dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index)
+{
+ unsigned long len = 0;
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index];
+ unsigned long slots_in_blk = prel->pr_slots_per_block_to_alloc;
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ len = sizeof(struct Dwarf_P_Relocation_Block_s) +
+ slots_in_blk * rel_rec_size;
+
+ data = (struct Dwarf_P_Relocation_Block_s *)
+ _dwarf_p_get_alloc(dbg, len);
+ if (!data) {
+ return DW_DLV_ERROR;
+ }
+
+ if (prel->pr_first_block) {
+ prel->pr_last_block->rb_next = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count += 1;
+
+ } else {
+
+ prel->pr_first_block = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count = 1;
+ }
+
+ data->rb_slots_in_block = slots_in_blk;
+ data->rb_next_slot_to_use = 0;
+ data->rb_where_to_add_next =
+ ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
+ data->rb_data = data->rb_where_to_add_next;
+
+ return DW_DLV_OK;
+
+}
+
+/*
+ Reserve a slot. return DW_DLV_OK if succeeds.
+
+ Return DW_DLV_ERROR if fails (malloc error).
+
+ Use the relrec_to_fill to pass back a pointer to
+ a slot space to use.
+*/
+int
+_dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg,
+ int base_sec_index, void **relrec_to_fill)
+{
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[base_sec_index];
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ char *ret_addr = 0;
+
+ data = prel->pr_last_block;
+ if ((data == 0) ||
+ (data->rb_next_slot_to_use >= data->rb_slots_in_block)) {
+ int res;
+
+ res = _dwarf_pro_alloc_reloc_slots(dbg, base_sec_index);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ data = prel->pr_last_block;
+ /* now we have an empty slot */
+ ret_addr = data->rb_where_to_add_next;
+
+ data->rb_where_to_add_next += rel_rec_size;
+ data->rb_next_slot_to_use += 1;
+
+ prel->pr_reloc_total_count += 1;
+
+ *relrec_to_fill = (void *) ret_addr;
+
+ return DW_DLV_OK;
+
+}
+
+/*
+ On success returns count of
+ .rel.* sections that are symbolic
+ thru count_of_relocation_sections.
+
+ On success, returns DW_DLV_OK.
+
+ If this is not a 'symbolic' run, returns
+ DW_DLV_NO_ENTRY.
+
+ No errors are possible.
+
+
+
+
+*/
+
+ /*ARGSUSED*/ int
+dwarf_get_relocation_info_count(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned *
+ count_of_relocation_sections,
+ int *drd_buffer_version,
+ Dwarf_Error * error)
+{
+ if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ int i;
+ unsigned int count = 0;
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
+ if (dbg->de_reloc_sect[i].pr_reloc_total_count > 0) {
+ ++count;
+ }
+ }
+ *count_of_relocation_sections = (Dwarf_Unsigned) count;
+ *drd_buffer_version = DWARF_DRD_BUFFER_VERSION;
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+int
+dwarf_get_relocation_info(Dwarf_P_Debug dbg,
+ Dwarf_Signed * elf_section_index,
+ Dwarf_Signed * elf_section_index_link,
+ Dwarf_Unsigned * relocation_buffer_count,
+ Dwarf_Relocation_Data * reldata_buffer,
+ Dwarf_Error * error)
+{
+ int next = dbg->de_reloc_next_to_return;
+
+ if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ int i;
+
+ for (i = next; i < NUM_DEBUG_SECTIONS; ++i) {
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[i];
+
+ if (prel->pr_reloc_total_count > 0) {
+ dbg->de_reloc_next_to_return = i + 1;
+
+
+ /* ASSERT: prel->.pr_block_count == 1 */
+
+ *elf_section_index = prel->pr_sect_num_of_reloc_sect;
+ *elf_section_index_link = dbg->de_elf_sects[i];
+ *relocation_buffer_count = prel->pr_reloc_total_count;
+ *reldata_buffer = (Dwarf_Relocation_Data)
+ (prel->pr_first_block->rb_data);
+ return DW_DLV_OK;
+ }
+ }
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc.h b/usr/src/lib/libdwarf/common/pro_reloc.h
new file mode 100644
index 0000000000..d2e6c67357
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc.h
@@ -0,0 +1,47 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+int _dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg,
+ int rel_sec_index,
+ Dwarf_Unsigned newslots);
+
+int _dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index);
+
+int _dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ void **relrec_to_fill);
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_stream.c b/usr/src/lib/libdwarf/common/pro_reloc_stream.c
new file mode 100644
index 0000000000..459779ceda
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_stream.c
@@ -0,0 +1,297 @@
+/*
+
+ Copyright (C) 2000,2001,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#else
+/* Set r_info as defined by ELF generic ABI */
+#define Set_REL32_info(r,s,t) ((r).r_info = ELF32_R_INFO(s,t))
+#define Set_REL64_info(r,s,t) ((r).r_info = ELF64_R_INFO(s,t))
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+#include "pro_reloc_stream.h"
+
+/*
+ Return DW_DLV_ERROR on malloc error or reltarget_length error.
+ Return DW_DLV_OK otherwise
+
+
+
+*/
+ /*ARGSUSED*/ int
+_dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+#if HAVE_ELF64_GETEHDR
+ REL64 *elf64_reloc = 0;
+ void *relrec_to_fill = 0;
+ int res = 0;
+ int rel_type = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+
+
+ if (type == dwarf_drt_data_reloc) {
+ if (reltarget_length == dbg->de_offset_size) {
+ rel_type = dbg->de_offset_reloc;
+ } else if (reltarget_length == dbg->de_pointer_size) {
+ rel_type = dbg->de_ptr_reloc;
+ } else {
+ return DW_DLV_ERROR;
+ }
+ } else if (type == dwarf_drt_segment_rel) {
+ rel_type = dbg->de_exc_reloc;
+ } else {
+ /* We are in trouble: improper use of stream relocations.
+ Someone else will diagnose */
+ rel_type = 0;
+ }
+
+ elf64_reloc = (REL64 *)relrec_to_fill;
+ elf64_reloc->r_offset = offset;
+ Set_REL64_info(*elf64_reloc, symidx, rel_type);
+ return DW_DLV_OK;
+#else /* !HAVE_ELF64_GETEHDR */
+ return DW_DLV_ERROR;
+#endif /* #if HAVE_ELF64_GETEHDR */
+}
+
+/*
+ Return DW_DLV_ERROR on malloc error or reltarget_length error.
+ Return DW_DLV_OK otherwise
+ a binary reloc: 32bit ABI
+*/
+int
+_dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ REL32 *elf32_reloc = 0;
+ void *relrec_to_fill = 0;
+ int res = 0;
+ int rel_type = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ if (type == dwarf_drt_data_reloc) {
+ if (reltarget_length == dbg->de_offset_size) {
+ rel_type = dbg->de_offset_reloc;
+ } else if (reltarget_length == dbg->de_pointer_size) {
+ rel_type = dbg->de_ptr_reloc;
+ } else {
+ return DW_DLV_ERROR;
+ }
+ } else if (type == dwarf_drt_segment_rel) {
+ rel_type = dbg->de_exc_reloc;
+ } else {
+ /* We are in trouble: improper use of stream relocations.
+ Someone else will diagnose */
+ rel_type = 0;
+ }
+
+ elf32_reloc = (REL32*)relrec_to_fill;
+ elf32_reloc->r_offset = (Elf32_Addr) offset;
+ Set_REL32_info(*elf32_reloc, (Dwarf_Word) symidx, rel_type);
+ return DW_DLV_OK;
+
+ /* get a slot, fill in the slot entry */
+}
+
+
+
+/*
+ Return DW_DLV_OK.
+ Never can really do anything: lengths cannot
+ be represented as end-start in a stream.
+
+*/
+ /*ARGSUSED*/ int
+_dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ return DW_DLV_OK;
+}
+
+
+/*
+ Ensure each stream is a single buffer and
+ add that single buffer to the set of stream buffers.
+
+ By creating a new buffer and copying if necessary.
+
+ Free the input set of buffers if we consolidate.
+ Return -1 on error (malloc failure)
+
+
+ Return DW_DLV_OK on success. Any other return indicates
+ malloc failed.
+
+*/
+int
+_dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count)
+{
+ unsigned long total_size = 0;
+ Dwarf_Small *data = 0;
+ int sec_index = 0;
+ unsigned long i = 0;
+ Dwarf_Error err = 0;
+ Dwarf_Error *error = &err;
+
+ Dwarf_Signed sec_count = 0;
+
+ Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
+ unsigned long ct = p_reloc->pr_reloc_total_count;
+ unsigned len = 0;
+ struct Dwarf_P_Relocation_Block_s *p_blk = 0;
+ struct Dwarf_P_Relocation_Block_s *p_blk_last = 0;
+ Dwarf_P_Per_Reloc_Sect prb = 0;
+
+ if (ct == 0) {
+ continue;
+ }
+ prb = &dbg->de_reloc_sect[i];
+ len = dbg->de_relocation_record_size;
+ ++sec_count;
+
+ total_size = ct * len;
+ sec_index = prb->pr_sect_num_of_reloc_sect;
+ if (sec_index == 0) {
+ /* Call de_callback_func or de_callback_func_b, getting
+ section number of reloc section. */
+ int rel_section_index = 0;
+ Dwarf_Unsigned name_idx = 0;
+ int int_name = 0;
+ int err = 0;
+
+ if (dbg->de_callback_func_b) {
+ rel_section_index =
+ dbg->de_callback_func_b(_dwarf_rel_section_names[i],
+ /* size */
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ 0,
+ /* info == link to sec rels apply to
+ */
+ dbg->de_elf_sects[i],
+ &name_idx, &err);
+ } else {
+ rel_section_index =
+ dbg->de_callback_func(_dwarf_rel_section_names[i],
+ /* size */
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ 0,
+ /* info == link to sec rels apply to */
+ dbg->de_elf_sects[i], &int_name, &err);
+ name_idx = int_name;
+ }
+ if (rel_section_index == -1) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ELF_SECT_ERR);
+ return (DW_DLV_ERROR);
+ }
+
+ }
+ prb->pr_sect_num_of_reloc_sect = rel_section_index;
+ sec_index = rel_section_index;
+ }
+ GET_CHUNK(dbg, sec_index, data, total_size, &err);
+ p_blk = p_reloc->pr_first_block;
+
+ /* following loop executes at least once. Effects the
+ consolidation to a single block or, if already a single
+ block, simply copies to the output buffer. And frees the
+ input block. The new block is in the de_debug_sects list. */
+ while (p_blk) {
+
+ unsigned long len =
+ p_blk->rb_where_to_add_next - p_blk->rb_data;
+
+ memcpy(data, p_blk->rb_data, len);
+
+
+ data += len;
+
+ p_blk_last = p_blk;
+ p_blk = p_blk->rb_next;
+
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
+ }
+ /* ASSERT: sum of len copied == total_size */
+
+ /*
+ We have copied the input, now drop the pointers to it. For
+ debugging, leave the other data untouched. */
+ p_reloc->pr_first_block = 0;
+ p_reloc->pr_last_block = 0;
+ }
+
+ *new_sec_count = sec_count;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_stream.h b/usr/src/lib/libdwarf/common/pro_reloc_stream.h
new file mode 100644
index 0000000000..892ea5baf3
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_stream.h
@@ -0,0 +1,63 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+int _dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int _dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int _dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+
+int _dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count);
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c
new file mode 100644
index 0000000000..22080a00cd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c
@@ -0,0 +1,276 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+/*#include <elfaccess.h> */
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+#include "pro_reloc_symbolic.h"
+
+/*
+ Return DW_DLV_ERROR on malloc error.
+ Return DW_DLV_OK otherwise
+*/
+
+int
+_dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ void *relrec_to_fill = 0;
+ int res = 0;
+ struct Dwarf_Relocation_Data_s *slotp;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+ slotp->drd_type = type;
+ slotp->drd_length = reltarget_length;
+ slotp->drd_offset = offset;
+ slotp->drd_symbol_index = symidx;
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Return DW_DLV_ERROR on malloc error.
+ Return DW_DLV_OK otherwise
+*/
+int
+_dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ void *relrec_to_fill = 0;
+ int res = 0;
+ struct Dwarf_Relocation_Data_s *slotp1 = 0;
+ struct Dwarf_Relocation_Data_s *slotp2 = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp1 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp2 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+
+ /* ASSERT: type == dwarf_drt_first_of_length_type_pair */
+ slotp1->drd_type = type;
+ slotp1->drd_length = reltarget_length;
+ slotp1->drd_offset = offset;
+ slotp1->drd_symbol_index = start_symidx;
+
+ slotp2->drd_type = dwarf_drt_second_of_length_pair;
+ slotp2->drd_length = reltarget_length;
+ slotp2->drd_offset = offset;
+ slotp2->drd_symbol_index = end_symidx;
+ return DW_DLV_OK;
+}
+
+/*
+ Reset whatever fields of Dwarf_P_Per_Reloc_Sect_s
+ we must to allow adding a fresh new single
+ block easily (block consolidation use only).
+
+*/
+static void
+_dwarf_reset_reloc_sect_info(struct Dwarf_P_Per_Reloc_Sect_s *pblk,
+ unsigned long ct)
+{
+
+
+ /* Do not zero pr_sect_num_of_reloc_sect */
+ pblk->pr_reloc_total_count = 0;
+ pblk->pr_first_block = 0;
+ pblk->pr_last_block = 0;
+ pblk->pr_block_count = 0;
+ pblk->pr_slots_per_block_to_alloc = ct;
+}
+
+/*
+ Ensure each stream is a single buffer and
+ add that single buffer to the set of stream buffers.
+
+ By creating a new buffer and copying if necessary.
+ (If > 1 block, reduce to 1 block)
+
+ Free the input set of buffers if we consolidate.
+
+ We pass back *new_sec_count as zero because we
+ are not creating normal sections for a .o, but
+ symbolic relocations, separately counted.
+
+ Return -1 on error (malloc failure)
+
+ Return DW_DLV_OK on success. Any other return indicates
+ malloc failed.
+*/
+int
+_dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count)
+{
+ /* unsigned long total_size =0; */
+ Dwarf_Small *data = 0;
+ int sec_index = 0;
+ int res = 0;
+ unsigned long i = 0;
+ Dwarf_Error error = 0;
+ Dwarf_Signed sec_count = 0;
+ Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
+ unsigned long ct = p_reloc->pr_reloc_total_count;
+ struct Dwarf_P_Relocation_Block_s *p_blk;
+ struct Dwarf_P_Relocation_Block_s *p_blk_last;
+ int err;
+ if (ct == 0) {
+ continue;
+ }
+
+ /* len = dbg->de_relocation_record_size; */
+ ++sec_count;
+
+ /* total_size = ct *len; */
+ sec_index = p_reloc->pr_sect_num_of_reloc_sect;
+ if (sec_index == 0) {
+ /* Call de_callback_func or de_callback_func_b,
+ getting section number of reloc section. */
+ int rel_section_index = 0;
+ int int_name = 0;
+ Dwarf_Unsigned name_idx = 0;
+
+ /*
+ This is a bit of a fake, as we do not really have true
+ elf sections at all. Just the data such might contain.
+ But this lets the caller eventually link things
+ together: without this call we would not know what rel
+ data goes with what section when we are asked for the
+ real arrays. */
+
+ if (dbg->de_callback_func_b) {
+ rel_section_index =
+ dbg->de_callback_func_b(_dwarf_rel_section_names[i],
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ SHN_UNDEF,
+ /* sec rels apply to */
+ dbg->de_elf_sects[i],
+ &name_idx, &err);
+ } else {
+ rel_section_index =
+ dbg->de_callback_func(_dwarf_rel_section_names[i],
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ SHN_UNDEF,
+ /* sec rels apply to, in elf, sh_info */
+ dbg->de_elf_sects[i], &int_name, &err);
+ name_idx = int_name;
+ }
+ if (rel_section_index == -1) {
+ {
+ _dwarf_p_error(dbg, &error, DW_DLE_ELF_SECT_ERR);
+ return (DW_DLV_ERROR);
+ }
+ }
+ p_reloc->pr_sect_num_of_reloc_sect = rel_section_index;
+ sec_index = rel_section_index;
+ }
+
+ p_blk = p_reloc->pr_first_block;
+
+ if (p_reloc->pr_block_count > 1) {
+ struct Dwarf_P_Relocation_Block_s *new_blk;
+
+ /* HACK , not normal interfaces, trashing p_reloc current
+ contents! */
+ _dwarf_reset_reloc_sect_info(p_reloc, ct);
+
+ /* Creating new single block for all 'ct' entries */
+ res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg, (int) i, ct);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ new_blk = p_reloc->pr_first_block;
+
+ data = (Dwarf_Small *) new_blk->rb_data;
+
+ /* The following loop does the consolidation to a single
+ block and frees the input block(s). */
+ do {
+ unsigned long len =
+ p_blk->rb_where_to_add_next - p_blk->rb_data;
+ memcpy(data, p_blk->rb_data, len);
+ data += len;
+ p_blk_last = p_blk;
+ p_blk = p_blk->rb_next;
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
+ } while (p_blk);
+ /* ASSERT: sum of len copied == total_size */
+ new_blk->rb_next_slot_to_use = ct;
+ new_blk->rb_where_to_add_next = (char *) data;
+ p_reloc->pr_reloc_total_count = ct;
+
+ /* have now created a single block, but no change in slots
+ used (pr_reloc_total_count) */
+ }
+ }
+ *new_sec_count = 0;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h
new file mode 100644
index 0000000000..3d03a47863
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h
@@ -0,0 +1,55 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+int _dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int
+ _dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+
+int _dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count);
diff --git a/usr/src/lib/libdwarf/common/pro_section.c b/usr/src/lib/libdwarf/common/pro_section.c
new file mode 100644
index 0000000000..6503c2cf09
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_section.c
@@ -0,0 +1,2221 @@
+/*
+
+ Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/*
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_line.h"
+#include "pro_frame.h"
+#include "pro_die.h"
+#include "pro_macinfo.h"
+#include "pro_types.h"
+
+#ifndef SHF_MIPS_NOSTRIP
+/* if this is not defined, we probably don't need it: just use 0 */
+#define SHF_MIPS_NOSTRIP 0
+#endif
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* must match up with pro_section.h defines of DEBUG_INFO etc
+and sectnames (below). REL_SEC_PREFIX is either ".rel" or ".rela"
+see pro_incl.h
+*/
+char *_dwarf_rel_section_names[] = {
+ REL_SEC_PREFIX ".debug_info",
+ REL_SEC_PREFIX ".debug_line",
+ REL_SEC_PREFIX ".debug_abbrev", /* no relocations on this, really */
+ REL_SEC_PREFIX ".debug_frame",
+ REL_SEC_PREFIX ".debug_aranges",
+ REL_SEC_PREFIX ".debug_pubnames",
+ REL_SEC_PREFIX ".debug_str",
+ REL_SEC_PREFIX ".debug_funcnames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_typenames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_varnames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_weaknames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_macinfo",
+ REL_SEC_PREFIX ".debug_loc"
+};
+
+/* names of sections. Ensure that it matches the defines
+ in pro_section.h, in the same order
+ Must match also _dwarf_rel_section_names above
+*/
+char *_dwarf_sectnames[] = {
+ ".debug_info",
+ ".debug_line",
+ ".debug_abbrev",
+ ".debug_frame",
+ ".debug_aranges",
+ ".debug_pubnames",
+ ".debug_str",
+ ".debug_funcnames", /* sgi extension */
+ ".debug_typenames", /* sgi extension */
+ ".debug_varnames", /* sgi extension */
+ ".debug_weaknames", /* sgi extension */
+ ".debug_macinfo",
+ ".debug_loc"
+};
+
+
+
+
+static Dwarf_Ubyte std_opcode_len[] = { 0, /* DW_LNS_copy */
+ 1, /* DW_LNS_advance_pc */
+ 1, /* DW_LNS_advance_line */
+ 1, /* DW_LNS_set_file */
+ 1, /* DW_LNS_set_column */
+ 0, /* DW_LNS_negate_stmt */
+ 0, /* DW_LNS_set_basic_block */
+ 0, /* DW_LNS_const_add_pc */
+ 1, /* DW_LNS_fixed_advance_pc */
+};
+
+/* struct to hold relocation entries. Its mantained as a linked
+ list of relocation structs, and will then be written at as a
+ whole into the relocation section. Whether its 32 bit or
+ 64 bit will be obtained from Dwarf_Debug pointer.
+*/
+
+typedef struct Dwarf_P_Rel_s *Dwarf_P_Rel;
+struct Dwarf_P_Rel_s {
+ Dwarf_P_Rel dr_next;
+ void *dr_rel_datap;
+};
+typedef struct Dwarf_P_Rel_Head_s *Dwarf_P_Rel_Head;
+struct Dwarf_P_Rel_Head_s {
+ struct Dwarf_P_Rel_s *drh_head;
+ struct Dwarf_P_Rel_s *drh_tail;
+};
+
+static int _dwarf_pro_generate_debugline(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static int _dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static int _dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static Dwarf_P_Abbrev _dwarf_pro_getabbrev(Dwarf_P_Die, Dwarf_P_Abbrev);
+static int _dwarf_pro_match_attr
+ (Dwarf_P_Attribute, Dwarf_P_Abbrev, int no_attr);
+
+/* these macros used as return value for below functions */
+#define OPC_INCS_ZERO -1
+#define OPC_OUT_OF_RANGE -2
+#define LINE_OUT_OF_RANGE -3
+static int _dwarf_pro_get_opc(Dwarf_Unsigned addr_adv, int line_adv);
+
+
+/* BEGIN_LEN_SIZE is the size of the 'length' field in total.
+ Which may be 4,8, or 12 bytes!
+ 4 is standard DWARF2.
+ 8 is non-standard MIPS-IRIX 64-bit.
+ 12 is standard DWARF3 for 64 bit offsets.
+ Used in various routines: local variable names
+ must match the names here.
+*/
+#define BEGIN_LEN_SIZE (uwordb_size + extension_size)
+
+/*
+ Return TRUE if we need the section, FALSE otherwise
+
+ If any of the 'line-data-related' calls were made
+ including file or directory entries,
+ produce .debug_line .
+
+*/
+static int
+dwarf_need_debug_line_section(Dwarf_P_Debug dbg)
+{
+ if (dbg->de_lines == NULL && dbg->de_file_entries == NULL
+ && dbg->de_inc_dirs == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ Convert debug information to a format such that
+ it can be written on disk.
+ Called exactly once per execution.
+*/
+Dwarf_Signed
+dwarf_transform_to_disk_form(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ /*
+ Section data in written out in a number of buffers. Each
+ _generate_*() function returns a cumulative count of buffers for
+ all the sections. get_section_bytes() returns pointers to these
+ buffers one at a time. */
+ int nbufs = 0;
+ int sect = 0;
+ int err = 0;
+ Dwarf_Unsigned du = 0;
+
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT);
+ }
+
+ /* Create dwarf section headers */
+ for (sect = 0; sect < NUM_DEBUG_SECTIONS; sect++) {
+ long flags = 0;
+
+ switch (sect) {
+
+ case DEBUG_INFO:
+ if (dbg->de_dies == NULL)
+ continue;
+ break;
+
+ case DEBUG_LINE:
+ if (dwarf_need_debug_line_section(dbg) == FALSE) {
+ continue;
+ }
+ break;
+
+ case DEBUG_ABBREV:
+ if (dbg->de_dies == NULL)
+ continue;
+ break;
+
+ case DEBUG_FRAME:
+ if (dbg->de_frame_cies == NULL)
+ continue;
+ flags = SHF_MIPS_NOSTRIP;
+ break;
+
+ case DEBUG_ARANGES:
+ if (dbg->de_arange == NULL)
+ continue;
+ break;
+
+ case DEBUG_PUBNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_pubname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_STR:
+ if (dbg->de_strings == NULL)
+ continue;
+ break;
+
+ case DEBUG_FUNCNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_funcname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_TYPENAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_typename].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_VARNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_varname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_WEAKNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_weakname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_MACINFO:
+ if (dbg->de_first_macinfo == NULL)
+ continue;
+ break;
+ case DEBUG_LOC:
+ /* not handled yet */
+ continue;
+ default:
+ /* logic error: missing a case */
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR, DW_DLV_NOCOUNT);
+ }
+ {
+ int new_base_elf_sect;
+
+ if (dbg->de_callback_func_b) {
+ new_base_elf_sect =
+ dbg->de_callback_func_b(_dwarf_sectnames[sect],
+ /* rec size */ 1,
+ SECTION_TYPE,
+ flags, SHN_UNDEF, 0, &du, &err);
+
+ } else {
+ int name_idx = 0;
+ new_base_elf_sect = dbg->de_callback_func(
+ _dwarf_sectnames[sect],
+ dbg->de_relocation_record_size,
+ SECTION_TYPE, flags,
+ SHN_UNDEF, 0,
+ &name_idx, &err);
+ du = name_idx;
+ }
+ if (new_base_elf_sect == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR,
+ DW_DLV_NOCOUNT);
+ }
+ dbg->de_elf_sects[sect] = new_base_elf_sect;
+
+ dbg->de_sect_name_idx[sect] = du;
+ }
+ }
+
+ nbufs = 0;
+
+ /*
+ Changing the order in which the sections are generated may cause
+ problems because of relocations. */
+
+ if (dwarf_need_debug_line_section(dbg) == TRUE) {
+ nbufs = _dwarf_pro_generate_debugline(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGLINE_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_frame_cies) {
+ nbufs = _dwarf_pro_generate_debugframe(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGFRAME_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+ if (dbg->de_first_macinfo) {
+ nbufs = _dwarf_pro_transform_macro_info_to_disk(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGMACINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_dies) {
+ nbufs = _dwarf_pro_generate_debuginfo(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_arange) {
+ nbufs = _dwarf_transform_arange_to_disk(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_pubname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_pubname,
+ DEBUG_PUBNAMES,
+ error);
+
+
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_funcname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_funcname,
+ DEBUG_FUNCNAMES,
+ error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_typename].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_typename,
+ DEBUG_TYPENAMES,
+ error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_varname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_varname,
+ DEBUG_VARNAMES,
+ error);
+
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_weakname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_weakname, DEBUG_WEAKNAMES, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ {
+ Dwarf_Signed new_secs = 0;
+ int res = 0;
+
+ res = dbg->de_transform_relocs_to_disk(dbg, &new_secs);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ nbufs += new_secs;
+ }
+ return nbufs;
+}
+
+
+/*---------------------------------------------------------------
+ Generate debug_line section
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debugline(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Inc_Dir curdir = 0;
+ Dwarf_P_F_Entry curentry = 0;
+ Dwarf_P_Line curline = 0;
+ Dwarf_P_Line prevline = 0;
+
+ /* all data named cur* are used to loop thru linked lists */
+
+ int sum_bytes = 0;
+ int prolog_size = 0;
+ unsigned char *data = 0; /* holds disk form data */
+ int elfsectno = 0;
+ unsigned char *start_line_sec = 0; /* pointer to the buffer at
+ section start */
+ /* temps for memcpy */
+ Dwarf_Unsigned du = 0;
+ Dwarf_Ubyte db = 0;
+ Dwarf_Half dh = 0;
+ int res = 0;
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+ int upointer_size = dbg->de_pointer_size;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+
+
+ sum_bytes = 0;
+
+ elfsectno = dbg->de_elf_sects[DEBUG_LINE];
+
+ /* include directories */
+ curdir = dbg->de_inc_dirs;
+ while (curdir) {
+ prolog_size += strlen(curdir->did_name) + 1;
+ curdir = curdir->did_next;
+ }
+ prolog_size++; /* last null following last directory
+ entry. */
+
+ /* file entries */
+ curentry = dbg->de_file_entries;
+ while (curentry) {
+ prolog_size +=
+ strlen(curentry->dfe_name) + 1 + curentry->dfe_nbytes;
+ curentry = curentry->dfe_next;
+ }
+ prolog_size++; /* last null byte */
+
+
+ prolog_size += BEGIN_LEN_SIZE + sizeof_uhalf(dbg) + /* version # */
+ uwordb_size + /* header length */
+ sizeof_ubyte(dbg) + /* min_instr length */
+ sizeof_ubyte(dbg) + /* default is_stmt */
+ sizeof_ubyte(dbg) + /* linebase */
+ sizeof_ubyte(dbg) + /* linerange */
+ sizeof_ubyte(dbg); /* opcode base */
+
+ /* length of table specifying # of opnds */
+ prolog_size += sizeof(std_opcode_len);
+
+ GET_CHUNK(dbg, elfsectno, data, prolog_size, error);
+ start_line_sec = data;
+
+ /* copy over the data */
+ /* total_length */
+ du = 0;
+ if (extension_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+ }
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ dh = VERSION;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dh,
+ sizeof(dh), sizeof(Dwarf_Half));
+ data += sizeof(Dwarf_Half);
+
+ /* header length */
+ du = prolog_size - (BEGIN_LEN_SIZE + sizeof(Dwarf_Half) +
+ uwordb_size);
+ {
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+ }
+ db = MIN_INST_LENGTH;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = DEFAULT_IS_STMT;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = (Dwarf_Ubyte) LINE_BASE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = LINE_RANGE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = OPCODE_BASE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) std_opcode_len,
+ sizeof(std_opcode_len), sizeof(std_opcode_len));
+ data += sizeof(std_opcode_len);
+
+ /* copy over include directories */
+ curdir = dbg->de_inc_dirs;
+ while (curdir) {
+ strcpy((char *) data, curdir->did_name);
+ data += strlen(curdir->did_name) + 1;
+ curdir = curdir->did_next;
+ }
+ *data = '\0'; /* last null */
+ data++;
+
+ /* copy file entries */
+ curentry = dbg->de_file_entries;
+ while (curentry) {
+ strcpy((char *) data, curentry->dfe_name);
+ data += strlen(curentry->dfe_name) + 1;
+ /* copies of leb numbers, no endian issues */
+ memcpy((void *) data,
+ (const void *) curentry->dfe_args, curentry->dfe_nbytes);
+ data += curentry->dfe_nbytes;
+ curentry = curentry->dfe_next;
+ }
+ *data = '\0';
+ data++;
+
+ sum_bytes += prolog_size;
+
+ curline = dbg->de_lines;
+ prevline = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (prevline == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, -1);
+ }
+ _dwarf_pro_reg_init(prevline);
+ /* generate opcodes for line numbers */
+ while (curline) {
+ int nbytes;
+ char *arg;
+ int opc;
+ int no_lns_copy; /* if lns copy opcode doesnt need to be
+ generated, if special opcode or end
+ sequence */
+ Dwarf_Unsigned addr_adv;
+ int line_adv; /* supposed to be a reasonably small
+ number, so the size should not be a
+ problem. ? */
+
+ no_lns_copy = 0;
+ if (curline->dpl_opc != 0) {
+ int inst_bytes; /* no of bytes in extended opcode */
+ char *str; /* hold leb encoded inst_bytes */
+ int str_nbytes; /* no of bytes in str */
+
+ switch (curline->dpl_opc) {
+ case DW_LNE_end_sequence:
+
+ /* Advance pc to end of text section. */
+ addr_adv = curline->dpl_address - prevline->dpl_address;
+ if (addr_adv > 0) {
+ db = DW_LNS_advance_pc;
+ res =
+ _dwarf_pro_encode_leb128_nm(addr_adv /
+ MIN_INST_LENGTH,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db, sizeof(db),
+ sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ /* leb, no endianness issue */
+ memcpy((void *) data, (const void *) buff1, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_address = curline->dpl_address;
+ }
+
+ /* first null byte */
+ db = 0;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* write length of extended opcode */
+ inst_bytes = sizeof(Dwarf_Ubyte);
+ res =
+ _dwarf_pro_encode_leb128_nm(inst_bytes, &str_nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data, str_nbytes, error);
+ memcpy((void *) data, (const void *) buff1, str_nbytes);
+ data += str_nbytes;
+ sum_bytes += str_nbytes;
+
+ /* write extended opcode */
+ db = DW_LNE_end_sequence;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ /* reset value to original values */
+ _dwarf_pro_reg_init(prevline);
+ no_lns_copy = 1;
+ /* this is set only for end_sequence, so that a
+ dw_lns_copy is not generated */
+ break;
+
+ case DW_LNE_set_address:
+
+ /* first null byte */
+ db = 0;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* write length of extended opcode */
+ inst_bytes = sizeof(Dwarf_Ubyte) + upointer_size;
+ res =
+ _dwarf_pro_encode_leb128_nm(inst_bytes, &str_nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data, str_nbytes, error);
+ str = buff1;
+ /* leb number, no endian issue */
+ memcpy((void *) data, (const void *) str, str_nbytes);
+ data += str_nbytes;
+ sum_bytes += str_nbytes;
+
+ /* write extended opcode */
+ db = DW_LNE_set_address;
+ GET_CHUNK(dbg, elfsectno, data, upointer_size +
+ sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* reloc for address */
+ res = dbg->de_reloc_name(dbg, DEBUG_LINE,
+ sum_bytes, /* r_offset */
+ curline->dpl_r_symidx,
+ dwarf_drt_data_reloc,
+ uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ /* write offset (address) */
+ du = curline->dpl_address;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+ sum_bytes += upointer_size;
+ prevline->dpl_address = curline->dpl_address;
+ no_lns_copy = 1;
+ break;
+ }
+ } else {
+ if (curline->dpl_file != prevline->dpl_file) {
+ db = DW_LNS_set_file;
+ res =
+ _dwarf_pro_encode_leb128_nm(curline->dpl_file,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes;
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_file = curline->dpl_file;
+ }
+ if (curline->dpl_column != prevline->dpl_column) {
+ db = DW_LNS_set_column;
+ res = _dwarf_pro_encode_leb128_nm(curline->dpl_column,
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes;
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_column = curline->dpl_column;
+ }
+ if (curline->dpl_is_stmt != prevline->dpl_is_stmt) {
+ db = DW_LNS_negate_stmt;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_is_stmt = curline->dpl_is_stmt;
+ }
+ if (curline->dpl_basic_block == true &&
+ prevline->dpl_basic_block == false) {
+ db = DW_LNS_set_basic_block;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = curline->dpl_basic_block;
+ }
+ addr_adv = curline->dpl_address - prevline->dpl_address;
+
+ line_adv = (int) (curline->dpl_line - prevline->dpl_line);
+ if ((addr_adv % MIN_INST_LENGTH) != 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_ADDRESS, -1);
+ }
+ if ((opc = _dwarf_pro_get_opc(addr_adv, line_adv)) > 0) {
+ no_lns_copy = 1;
+ db = opc;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_address = curline->dpl_address;
+ prevline->dpl_line = curline->dpl_line;
+ } else {
+ if (addr_adv > 0) {
+ db = DW_LNS_advance_pc;
+ res =
+ _dwarf_pro_encode_leb128_nm(addr_adv /
+ MIN_INST_LENGTH,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_address = curline->dpl_address;
+ }
+ if (line_adv != 0) {
+ db = DW_LNS_advance_line;
+ res = _dwarf_pro_encode_signed_leb128_nm(line_adv,
+ &nbytes,
+ buff1,
+ sizeof
+ (buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db, sizeof(db),
+ sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_line = curline->dpl_line;
+ }
+ }
+ } /* ends else for opc != 0 */
+ if (no_lns_copy == 0) { /* if not a special or dw_lne_end_seq
+ generate a matrix line */
+ db = DW_LNS_copy;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ }
+ curline = curline->dpl_next;
+ }
+
+ /* write total length field */
+ du = sum_bytes - BEGIN_LEN_SIZE;
+ {
+ start_line_sec += extension_size;
+ WRITE_UNALIGNED(dbg, (void *) start_line_sec,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+/*---------------------------------------------------------------
+ Generate debug_frame section
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ int elfsectno = 0;
+ int i = 0;
+ int firsttime = 1;
+ int pad = 0; /* Pad for padding to align cies and fdes */
+ Dwarf_P_Cie curcie = 0;
+ Dwarf_P_Fde curfde = 0;
+ unsigned char *data = 0;
+ Dwarf_sfixed dsw = 0;
+ Dwarf_Unsigned du = 0;
+ Dwarf_Ubyte db = 0;
+ long *cie_offs = 0; /* Holds byte offsets for links to fde's */
+ unsigned long cie_length = 0;
+ int cie_no = 0;
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+ int upointer_size = dbg->de_pointer_size;
+ Dwarf_Unsigned cur_off = 0; /* current offset of written data, held
+ for relocation info */
+
+ elfsectno = dbg->de_elf_sects[DEBUG_FRAME];
+
+ curcie = dbg->de_frame_cies;
+ cie_length = 0;
+ cur_off = 0;
+ cie_offs = (long *)
+ _dwarf_p_get_alloc(dbg, sizeof(long) * dbg->de_n_cie);
+ if (cie_offs == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ /* Generate cie number as we go along. This writes
+ all CIEs first before any FDEs, which is rather
+ different from the order a compiler might like (which
+ might be each CIE followed by its FDEs then the next CIE, and
+ so on). */
+ cie_no = 1;
+ while (curcie) {
+ char *code_al = 0;
+ int c_bytes = 0;
+ char *data_al = 0;
+ int d_bytes = 0;
+ int res = 0;
+ char buff1[ENCODE_SPACE_NEEDED];
+ char buff2[ENCODE_SPACE_NEEDED];
+ char buff3[ENCODE_SPACE_NEEDED];
+ char *augmentation = 0;
+ char *augmented_al = 0;
+ long augmented_fields_length = 0;
+ int a_bytes = 0;
+
+ res = _dwarf_pro_encode_leb128_nm(curcie->cie_code_align,
+ &c_bytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ /* Before April 1999, the following was using an unsigned
+ encode. That worked ok even though the decoder used the
+ correct signed leb read, but doing the encode correctly
+ (according to the dwarf spec) saves space in the output file
+ and is completely compatible.
+
+ Note the actual stored amount on MIPS was 10 bytes (!) to
+ store the value -4. (hex)fc ffffffff ffffffff 01 The
+ libdwarf consumer consumed all 10 bytes too!
+
+ old version res =
+ _dwarf_pro_encode_leb128_nm(curcie->cie_data_align,
+
+ below is corrected signed version. */
+ res = _dwarf_pro_encode_signed_leb128_nm(curcie->cie_data_align,
+ &d_bytes,
+ buff2, sizeof(buff2));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ code_al = buff1;
+ data_al = buff2;
+
+ /* get the correct offset */
+ if (firsttime) {
+ cie_offs[cie_no - 1] = 0;
+ firsttime = 0;
+ } else {
+ cie_offs[cie_no - 1] = cie_offs[cie_no - 2] +
+ (long) cie_length + BEGIN_LEN_SIZE;
+ }
+ cie_no++;
+ augmentation = curcie->cie_aug;
+ if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ augmented_fields_length = 0;
+ res = _dwarf_pro_encode_leb128_nm(augmented_fields_length,
+ &a_bytes, buff3,
+ sizeof(buff3));
+ augmented_al = buff3;
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ cie_length = uwordb_size + /* cie_id */
+ sizeof(Dwarf_Ubyte) + /* cie version */
+ strlen(curcie->cie_aug) + 1 + /* augmentation */
+ c_bytes + /* code alignment factor */
+ d_bytes + /* data alignment factor */
+ sizeof(Dwarf_Ubyte) + /* return reg address */
+ a_bytes + /* augmentation length */
+ curcie->cie_inst_bytes;
+ } else {
+ cie_length = uwordb_size + /* cie_id */
+ sizeof(Dwarf_Ubyte) + /* cie version */
+ strlen(curcie->cie_aug) + 1 + /* augmentation */
+ c_bytes + d_bytes + sizeof(Dwarf_Ubyte) + /* return
+ reg
+ address
+ */
+ curcie->cie_inst_bytes;
+ }
+ pad = (int) PADDING(cie_length, upointer_size);
+ cie_length += pad;
+ GET_CHUNK(dbg, elfsectno, data, cie_length +
+ BEGIN_LEN_SIZE, error);
+ if (extension_size) {
+ Dwarf_Unsigned x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+
+ }
+ du = cie_length;
+ /* total length of cie */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ /* cie-id is a special value. */
+ du = DW_CIE_ID;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ db = curcie->cie_version;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ strcpy((char *) data, curcie->cie_aug);
+ data += strlen(curcie->cie_aug) + 1;
+ memcpy((void *) data, (const void *) code_al, c_bytes);
+ data += c_bytes;
+ memcpy((void *) data, (const void *) data_al, d_bytes);
+ data += d_bytes;
+ db = curcie->cie_ret_reg;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+
+ if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ memcpy((void *) data, (const void *) augmented_al, a_bytes);
+ data += a_bytes;
+ }
+ memcpy((void *) data, (const void *) curcie->cie_inst,
+ curcie->cie_inst_bytes);
+ data += curcie->cie_inst_bytes;
+ for (i = 0; i < pad; i++) {
+ *data = DW_CFA_nop;
+ data++;
+ }
+ curcie = curcie->cie_next;
+ }
+ /* calculate current offset */
+ cur_off = cie_offs[cie_no - 2] + cie_length + BEGIN_LEN_SIZE;
+
+ /* write out fde's */
+ curfde = dbg->de_frame_fdes;
+ while (curfde) {
+ Dwarf_P_Frame_Pgm curinst = 0;
+ long fde_length = 0;
+ int pad = 0;
+ Dwarf_P_Cie cie_ptr = 0;
+ Dwarf_Word cie_index = 0;
+ Dwarf_Word index = 0;
+ int oet_length = 0;
+ int afl_length = 0;
+ int res = 0;
+ int v0_augmentation = 0;
+#if 0
+ unsigned char *fde_start_point = 0;
+#endif
+ char afl_buff[ENCODE_SPACE_NEEDED];
+
+ /* Find the CIE associated with this fde. */
+ cie_ptr = dbg->de_frame_cies;
+ cie_index = curfde->fde_cie;
+ index = 1; /* The cie_index of the first cie is 1,
+ not 0. */
+ while (cie_ptr && index < cie_index) {
+ cie_ptr = cie_ptr->cie_next;
+ index++;
+ }
+ if (cie_ptr == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_NULL, -1);
+ }
+
+ if (strcmp(cie_ptr->cie_aug, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ v0_augmentation = 1;
+ oet_length = sizeof(Dwarf_sfixed);
+ /* encode the length of augmented fields. */
+ res = _dwarf_pro_encode_leb128_nm(oet_length,
+ &afl_length, afl_buff,
+ sizeof(afl_buff));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+
+ fde_length = curfde->fde_n_bytes + BEGIN_LEN_SIZE + /* cie
+ pointer
+ */
+ upointer_size + /* initial loc */
+ upointer_size + /* address range */
+ afl_length + /* augmented field length */
+ oet_length; /* exception_table offset */
+ } else {
+ fde_length = curfde->fde_n_bytes + BEGIN_LEN_SIZE + /* cie
+ pointer
+ */
+ upointer_size + /* initial loc */
+ upointer_size; /* address range */
+ }
+
+
+ if (curfde->fde_die) {
+ /* IRIX/MIPS extension:
+ Using fde offset, generate DW_AT_MIPS_fde attribute for the
+ die corresponding to this fde. */
+ if(_dwarf_pro_add_AT_fde(dbg, curfde->fde_die, cur_off,
+ error) < 0) {
+ return -1;
+ }
+ }
+
+ /* store relocation for cie pointer */
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME, cur_off +
+ BEGIN_LEN_SIZE /* r_offset */,
+ dbg->de_sect_name_idx[DEBUG_FRAME],
+ dwarf_drt_data_reloc, uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ /* store relocation information for initial location */
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME,
+ cur_off + BEGIN_LEN_SIZE +
+ upointer_size /* r_offset */,
+ curfde->fde_r_symidx,
+ dwarf_drt_data_reloc, upointer_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ /* Store the relocation information for the
+ offset_into_exception_info field, if the offset is valid (0
+ is a valid offset). */
+ if (v0_augmentation &&
+ curfde->fde_offset_into_exception_tables >= 0) {
+
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME,
+ /* r_offset, where in cie this
+ field starts */
+ cur_off + BEGIN_LEN_SIZE +
+ uwordb_size + 2 * upointer_size +
+ afl_length,
+ curfde->fde_exception_table_symbol,
+ dwarf_drt_segment_rel,
+ sizeof(Dwarf_sfixed));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ }
+
+ /* adjust for padding */
+ pad = (int) PADDING(fde_length, upointer_size);
+ fde_length += pad;
+
+
+ /* write out fde */
+ GET_CHUNK(dbg, elfsectno, data, fde_length + BEGIN_LEN_SIZE,
+ error);
+#if 0
+ fde_start_point = data;
+#endif
+ du = fde_length;
+ {
+ if (extension_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+ }
+ /* length */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ /* offset to cie */
+ du = cie_offs[curfde->fde_cie - 1];
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ du = curfde->fde_initloc;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+
+ if (dbg->de_reloc_pair &&
+ curfde->fde_end_symbol != 0 &&
+ curfde->fde_addr_range == 0) {
+ /* symbolic reloc, need reloc for length What if we
+ really know the length? If so, should use the other
+ part of 'if'. */
+ Dwarf_Unsigned val;
+
+ res = dbg->de_reloc_pair(dbg,
+ /* DEBUG_ARANGES, */
+ DEBUG_FRAME, cur_off + 2 * uwordb_size + upointer_size, /* r_offset
+ */
+ curfde->fde_r_symidx,
+ curfde->fde_end_symbol,
+ dwarf_drt_first_of_length_pair,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* arrange pre-calc so assem text can do .word end -
+ begin + val (gets val from stream) */
+ val = curfde->fde_end_symbol_offset -
+ curfde->fde_initloc;
+ WRITE_UNALIGNED(dbg, data,
+ (const void *) &val,
+ sizeof(val), upointer_size);
+ data += upointer_size;
+ } else {
+
+ du = curfde->fde_addr_range;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+ }
+ }
+
+ if (v0_augmentation) {
+ /* write the encoded augmented field length. */
+ memcpy((void *) data, (const void *) afl_buff, afl_length);
+ data += afl_length;
+ /* write the offset_into_exception_tables field. */
+ dsw =
+ (Dwarf_sfixed) curfde->fde_offset_into_exception_tables;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dsw,
+ sizeof(dsw), sizeof(Dwarf_sfixed));
+ data += sizeof(Dwarf_sfixed);
+ }
+
+ curinst = curfde->fde_inst;
+ if(curfde->fde_block) {
+ unsigned long size = curfde->fde_inst_block_size;
+ memcpy((void *) data, (const void *) curfde->fde_block, size);
+ data += size;
+ } else {
+ while (curinst) {
+ db = curinst->dfp_opcode;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+#if 0
+ if (curinst->dfp_sym_index) {
+ int res = dbg->de_reloc_name(dbg,
+ DEBUG_FRAME,
+ /* r_offset = */
+ (data - fde_start_point) + cur_off + uwordb_size,
+ curinst->dfp_sym_index,
+ dwarf_drt_data_reloc,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+#endif
+ memcpy((void *) data,
+ (const void *) curinst->dfp_args,
+ curinst->dfp_nbytes);
+ data += curinst->dfp_nbytes;
+ curinst = curinst->dfp_next;
+ }
+ }
+ /* padding */
+ for (i = 0; i < pad; i++) {
+ *data = DW_CFA_nop;
+ data++;
+ }
+ cur_off += fde_length + uwordb_size;
+ curfde = curfde->fde_next;
+ }
+
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+/*
+ These functions remember all the markers we see along
+ with the right offset in the .debug_info section so that
+ we can dump them all back to the user with the section info.
+*/
+
+static int
+marker_init(Dwarf_P_Debug dbg,
+ unsigned count)
+{
+ dbg->de_marker_n_alloc = count;
+ dbg->de_markers = NULL;
+ if (count > 0) {
+ dbg->de_markers = _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Marker_s) *
+ dbg->de_marker_n_alloc);
+ if (dbg->de_markers == NULL) {
+ dbg->de_marker_n_alloc = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+marker_add(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Unsigned marker)
+{
+ if (dbg->de_marker_n_alloc >= (dbg->de_marker_n_used + 1)) {
+ unsigned n = dbg->de_marker_n_used++;
+ dbg->de_markers[n].ma_offset = offset;
+ dbg->de_markers[n].ma_marker = marker;
+ return 0;
+ }
+
+ return -1;
+}
+
+Dwarf_Signed
+dwarf_get_die_markers(Dwarf_P_Debug dbg,
+ Dwarf_P_Marker * marker_list, /* pointer to a pointer */
+ Dwarf_Unsigned * marker_count,
+ Dwarf_Error * error)
+{
+ if (marker_list == NULL || marker_count == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_BADADDR);
+ }
+ if (dbg->de_marker_n_used != dbg->de_marker_n_alloc) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_MAF, DW_DLV_BADADDR);
+ }
+
+ *marker_list = dbg->de_markers;
+ *marker_count = dbg->de_marker_n_used;
+ return DW_DLV_OK;
+}
+
+/* These functions provide the offsets of DW_FORM_string
+ attributes in the section section_index. These information
+ will enable a producer app that is generating assembly
+ text output to easily emit those attributes in ascii form
+ without having to decode the byte stream.
+ */
+static int
+string_attr_init (Dwarf_P_Debug dbg,
+ Dwarf_Signed section_index,
+ unsigned count)
+{
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index];
+
+ sect_sa->sect_sa_n_alloc = count;
+ sect_sa->sect_sa_list = NULL;
+ if (count > 0) {
+ sect_sa->sect_sa_section_number = section_index;
+ sect_sa->sect_sa_list = _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_String_Attr_s)
+ * sect_sa->sect_sa_n_alloc);
+ if (sect_sa->sect_sa_list == NULL) {
+ sect_sa->sect_sa_n_alloc = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+string_attr_add (Dwarf_P_Debug dbg,
+ Dwarf_Signed section_index,
+ Dwarf_Unsigned offset,
+ Dwarf_P_Attribute attr)
+{
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index];
+ if (sect_sa->sect_sa_n_alloc >= (sect_sa->sect_sa_n_used + 1)) {
+ unsigned n = sect_sa->sect_sa_n_used++;
+ sect_sa->sect_sa_list[n].sa_offset = offset;
+ sect_sa->sect_sa_list[n].sa_nbytes = attr->ar_nbytes;
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+dwarf_get_string_attributes_count(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned *
+ count_of_sa_sections,
+ int *drd_buffer_version,
+ Dwarf_Error *error)
+{
+ int i;
+ unsigned int count = 0;
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
+ if (dbg->de_sect_string_attr[i].sect_sa_n_used > 0) {
+ ++count;
+ }
+ }
+ *count_of_sa_sections = (Dwarf_Unsigned) count;
+ *drd_buffer_version = DWARF_DRD_BUFFER_VERSION;
+
+ return DW_DLV_OK;
+}
+
+int
+dwarf_get_string_attributes_info(Dwarf_P_Debug dbg,
+ Dwarf_Signed *elf_section_index,
+ Dwarf_Unsigned *sect_sa_buffer_count,
+ Dwarf_P_String_Attr *sect_sa_buffer,
+ Dwarf_Error *error)
+{
+ int i;
+ int next = dbg->de_sect_sa_next_to_return;
+
+ for (i = next; i < NUM_DEBUG_SECTIONS; ++i) {
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[i];
+ if (sect_sa->sect_sa_n_used > 0) {
+ dbg->de_sect_sa_next_to_return = i + 1;
+ *elf_section_index = sect_sa->sect_sa_section_number;
+ *sect_sa_buffer_count = sect_sa->sect_sa_n_used;
+ *sect_sa_buffer = sect_sa->sect_sa_list;
+ return DW_DLV_OK;
+ }
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+
+/*---------------------------------------------------------------
+ Generate debug_info and debug_abbrev sections
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ int elfsectno_of_debug_info = 0;
+ int abbrevsectno = 0;
+ unsigned char *data = 0;
+ int cu_header_size = 0;
+ Dwarf_P_Abbrev curabbrev = 0;
+ Dwarf_P_Abbrev abbrev_head = 0;
+ Dwarf_P_Abbrev abbrev_tail = 0;
+ Dwarf_P_Die curdie = 0;
+ Dwarf_P_Die first_child = 0;
+ Dwarf_Word dw = 0;
+ Dwarf_Unsigned du = 0;
+ Dwarf_Half dh = 0;
+ Dwarf_Ubyte db = 0;
+ Dwarf_Half version = 0; /* Need 2 byte quantity. */
+ Dwarf_Unsigned die_off = 0; /* Offset of die in debug_info. */
+ int n_abbrevs = 0;
+ int res = 0;
+ unsigned marker_count = 0;
+ unsigned string_attr_count = 0;
+ unsigned string_attr_offset = 0;
+
+ Dwarf_Small *start_info_sec = 0;
+
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+
+ abbrev_head = abbrev_tail = NULL;
+ elfsectno_of_debug_info = dbg->de_elf_sects[DEBUG_INFO];
+
+ /* write cu header */
+ cu_header_size = BEGIN_LEN_SIZE + sizeof(Dwarf_Half) + /* version
+ stamp
+ */
+ uwordb_size + /* offset into abbrev table */
+ sizeof(Dwarf_Ubyte); /* size of target address */
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data, cu_header_size,
+ error);
+ start_info_sec = data;
+ if (extension_size) {
+ du = DISTINGUISHED_VALUE;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), extension_size);
+ data += extension_size;
+ }
+ du = 0; /* length of debug_info, not counting
+ this field itself (unknown at this
+ point). */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ version = CURRENT_VERSION_STAMP; /* assume this length will not
+ change */
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &version,
+ sizeof(version), sizeof(Dwarf_Half));
+ data += sizeof(Dwarf_Half);
+
+ du = 0; /* offset into abbrev table, not yet
+ known. */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+
+ db = dbg->de_pointer_size;
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), 1);
+
+ /* We have filled the chunk we got with GET_CHUNK. At this point we
+ no longer dare use "data" or "start_info_sec" as a pointer any
+ longer except to refer to that first small chunk for the cu
+ header. */
+
+ curdie = dbg->de_dies;
+
+ /* create AT_macro_info if appropriate */
+ if (dbg->de_first_macinfo != NULL) {
+ if (_dwarf_pro_add_AT_macro_info(dbg, curdie, 0, error) < 0)
+ return -1;
+ }
+
+ /* create AT_stmt_list attribute if necessary */
+ if (dwarf_need_debug_line_section(dbg) == TRUE)
+ if (_dwarf_pro_add_AT_stmt_list(dbg, curdie, error) < 0)
+ return -1;
+
+ die_off = cu_header_size;
+
+ /*
+ Relocation for abbrev offset in cu header store relocation
+ record in linked list */
+ res = dbg->de_reloc_name(dbg, DEBUG_INFO, BEGIN_LEN_SIZE +
+ sizeof(Dwarf_Half),
+ /* r_offset */
+ dbg->de_sect_name_idx[DEBUG_ABBREV],
+ dwarf_drt_data_reloc, uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ /* pass 0: only top level dies, add at_sibling attribute to those
+ dies with children */
+ first_child = curdie->di_child;
+ while (first_child && first_child->di_right) {
+ if (first_child->di_child)
+ dwarf_add_AT_reference(dbg,
+ first_child,
+ DW_AT_sibling,
+ first_child->di_right, error);
+ first_child = first_child->di_right;
+ }
+
+ /* pass 1: create abbrev info, get die offsets, calc relocations */
+ marker_count = 0;
+ string_attr_count = 0;
+ while (curdie != NULL) {
+ int nbytes = 0;
+ Dwarf_P_Attribute curattr;
+ Dwarf_P_Attribute new_first_attr;
+ Dwarf_P_Attribute new_last_attr;
+ char *space = 0;
+ int res = 0;
+ char buff1[ENCODE_SPACE_NEEDED];
+ int i = 0;
+
+ curdie->di_offset = die_off;
+
+ if (curdie->di_marker != 0)
+ marker_count++;
+
+ curabbrev = _dwarf_pro_getabbrev(curdie, abbrev_head);
+ if (curabbrev == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ if (abbrev_head == NULL) {
+ n_abbrevs = 1;
+ curabbrev->abb_idx = n_abbrevs;
+ abbrev_tail = abbrev_head = curabbrev;
+ } else {
+ /* check if its a new abbreviation, if yes, add to tail */
+ if (curabbrev->abb_idx == 0) {
+ n_abbrevs++;
+ curabbrev->abb_idx = n_abbrevs;
+ abbrev_tail->abb_next = curabbrev;
+ abbrev_tail = curabbrev;
+ }
+ }
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_idx,
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ space = _dwarf_p_get_alloc(dbg, nbytes);
+ if (space == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ memcpy(space, buff1, nbytes);
+ curdie->di_abbrev = space;
+ curdie->di_abbrev_nbytes = nbytes;
+ die_off += nbytes;
+
+ /* Resorting the attributes!! */
+ new_first_attr = new_last_attr = NULL;
+ curattr = curdie->di_attrs;
+ for (i = 0; i < (int)curabbrev->abb_n_attr; i++) {
+ Dwarf_P_Attribute ca;
+ Dwarf_P_Attribute cl;
+
+ /* The following should always find an attribute! */
+ for (ca = cl = curattr;
+ ca && curabbrev->abb_attrs[i] != ca->ar_attribute;
+ cl = ca, ca = ca->ar_next)
+ {
+ }
+
+ if (!ca) {
+ DWARF_P_DBG_ERROR(dbg,DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ /* Remove the attribute from the old list. */
+ if (ca == curattr) {
+ curattr = ca->ar_next;
+ } else {
+ cl->ar_next = ca->ar_next;
+ }
+
+ ca->ar_next = NULL;
+
+ /* Add the attribute to the new list. */
+ if (new_first_attr == NULL) {
+ new_first_attr = new_last_attr = ca;
+ } else {
+ new_last_attr->ar_next = ca;
+ new_last_attr = ca;
+ }
+ }
+
+ curdie->di_attrs = new_first_attr;
+
+ curattr = curdie->di_attrs;
+
+ while (curattr) {
+ if (curattr->ar_rel_type != R_MIPS_NONE) {
+ switch (curattr->ar_attribute) {
+ case DW_AT_stmt_list:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_LINE];
+ break;
+ case DW_AT_MIPS_fde:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_FRAME];
+ break;
+ case DW_AT_macro_info:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_MACINFO];
+ break;
+ default:
+ break;
+ }
+ res = dbg->de_reloc_name(dbg, DEBUG_INFO, die_off + curattr->ar_rel_offset, /* r_offset
+ */
+ curattr->ar_rel_symidx,
+ dwarf_drt_data_reloc,
+ curattr->ar_reloc_len);
+
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ }
+ if (curattr->ar_attribute_form == DW_FORM_string) {
+ string_attr_count++;
+ }
+ die_off += curattr->ar_nbytes;
+ curattr = curattr->ar_next;
+ }
+
+ /* depth first search */
+ if (curdie->di_child)
+ curdie = curdie->di_child;
+ else {
+ while (curdie != NULL && curdie->di_right == NULL) {
+ curdie = curdie->di_parent;
+ die_off++; /* since we are writing a null die at
+ the end of each sibling chain */
+ }
+ if (curdie != NULL)
+ curdie = curdie->di_right;
+ }
+
+ } /* end while (curdie != NULL) */
+
+ res = marker_init(dbg, marker_count);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+ res = string_attr_init(dbg, DEBUG_INFO, string_attr_count);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ /* Pass 2: Write out the die information Here 'data' is a
+ temporary, one block for each GET_CHUNK. 'data' is overused. */
+ curdie = dbg->de_dies;
+ while (curdie != NULL) {
+ Dwarf_P_Attribute curattr;
+
+ if (curdie->di_marker != 0) {
+ res = marker_add(dbg, curdie->di_offset, curdie->di_marker);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+ }
+
+ /* index to abbreviation table */
+ GET_CHUNK(dbg, elfsectno_of_debug_info,
+ data, curdie->di_abbrev_nbytes, error);
+
+ memcpy((void *) data,
+ (const void *) curdie->di_abbrev,
+ curdie->di_abbrev_nbytes);
+
+ /* Attribute values - need to fill in all form attributes */
+ curattr = curdie->di_attrs;
+ string_attr_offset = curdie->di_offset + curdie->di_abbrev_nbytes;
+
+ while (curattr) {
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data,
+ (unsigned long) curattr->ar_nbytes, error);
+ switch (curattr->ar_attribute_form) {
+ case DW_FORM_ref1:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ db = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ break;
+ }
+ case DW_FORM_ref2:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xffff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ dh = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &dh,
+ sizeof(dh), sizeof(Dwarf_Half));
+ break;
+ }
+ case DW_FORM_ref_addr:
+ {
+ /* curattr->ar_ref_die == NULL!
+ *
+ * ref_addr doesn't take a CU-offset.
+ * This is different than other refs.
+ * This value will be set by the user of the
+ * producer library using a relocation.
+ * No need to set a value here.
+ */
+#if 0
+ du = curattr->ar_ref_die->di_offset;
+ {
+ /* ref to offset of die */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ }
+#endif
+ break;
+
+ }
+ case DW_FORM_ref4:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xffffffff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ dw = (Dwarf_Word) curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &dw,
+ sizeof(dw), sizeof(Dwarf_ufixed));
+ break;
+ }
+ case DW_FORM_ref8:
+ du = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), sizeof(Dwarf_Unsigned));
+ break;
+ case DW_FORM_ref_udata:
+ { /* unsigned leb128 offset */
+
+ int nbytes;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+ res =
+ _dwarf_pro_encode_leb128_nm(curattr->
+ ar_ref_die->
+ di_offset, &nbytes,
+ buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ memcpy(data, buff1, nbytes);
+ break;
+ }
+ default:
+ memcpy((void *) data,
+ (const void *) curattr->ar_data,
+ curattr->ar_nbytes);
+ break;
+ }
+ if (curattr->ar_attribute_form == DW_FORM_string) {
+ string_attr_add(dbg, DEBUG_INFO, string_attr_offset, curattr);
+ }
+ string_attr_offset += curattr->ar_nbytes;
+ curattr = curattr->ar_next;
+ }
+
+ /* depth first search */
+ if (curdie->di_child)
+ curdie = curdie->di_child;
+ else {
+ while (curdie != NULL && curdie->di_right == NULL) {
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data, 1, error);
+ *data = '\0';
+ curdie = curdie->di_parent;
+ }
+ if (curdie != NULL)
+ curdie = curdie->di_right;
+ }
+ } /* end while (curdir != NULL) */
+
+ /* Write out debug_info size */
+ /* Dont include length field or extension bytes */
+ du = die_off - BEGIN_LEN_SIZE;
+ WRITE_UNALIGNED(dbg, (void *) (start_info_sec + extension_size),
+ (const void *) &du, sizeof(du), uwordb_size);
+
+
+ data = 0; /* Emphasise not usable now */
+
+ /* Write out debug_abbrev section */
+ abbrevsectno = dbg->de_elf_sects[DEBUG_ABBREV];
+
+ curabbrev = abbrev_head;
+ while (curabbrev) {
+ char *val;
+ int nbytes;
+ int idx;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_idx, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ val = buff1;
+ memcpy((void *) data, (const void *) val, nbytes);
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_tag, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ db = curabbrev->abb_children;
+ GET_CHUNK(dbg, abbrevsectno, data, sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+
+ /* add attributes and forms */
+ for (idx = 0; idx < curabbrev->abb_n_attr; idx++) {
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_attrs[idx],
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_forms[idx],
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ }
+ GET_CHUNK(dbg, abbrevsectno, data, 2, error); /* two zeros,
+ for last
+ entry, see
+ dwarf2 sec
+ 7.5.3 */
+ *data = 0;
+ data++;
+ *data = 0;
+
+ curabbrev = curabbrev->abb_next;
+ }
+
+ GET_CHUNK(dbg, abbrevsectno, data, 1, error); /* one zero,
+ for end of
+ cu, see
+ dwarf2 sec
+ 7.5.3 */
+ *data = 0;
+
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+
+/*---------------------------------------------------------------------
+ Get a buffer of section data.
+ section_idx is the elf-section number that this data applies to.
+ length shows length of returned data
+----------------------------------------------------------------------*/
+ /*ARGSUSED*/ /* pretend all args used */
+ Dwarf_Ptr
+dwarf_get_section_bytes(Dwarf_P_Debug dbg,
+ Dwarf_Signed dwarf_section,
+ Dwarf_Signed * section_idx,
+ Dwarf_Unsigned * length, Dwarf_Error * error)
+{
+ Dwarf_Ptr buf;
+
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, NULL);
+ }
+
+ if (dbg->de_debug_sects == 0) {
+ /* no more data !! */
+ return NULL;
+ }
+ if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) {
+ /* no data ever entered !! */
+ return NULL;
+ }
+ *section_idx = dbg->de_debug_sects->ds_elf_sect_no;
+ *length = dbg->de_debug_sects->ds_nbytes;
+
+ buf = (Dwarf_Ptr *) dbg->de_debug_sects->ds_data;
+
+ dbg->de_debug_sects = dbg->de_debug_sects->ds_next;
+
+ /* We may want to call the section stuff more than once: see
+ dwarf_reset_section_bytes() do not do: dbg->de_n_debug_sect--; */
+
+ return buf;
+}
+
+/*
+ No errors possible.
+*/
+void
+dwarf_reset_section_bytes(Dwarf_P_Debug dbg)
+{
+ dbg->de_debug_sects = dbg->de_first_debug_sect;
+ /* No need to reset; commented out decrement. dbg->de_n_debug_sect
+ = ???; */
+ dbg->de_reloc_next_to_return = 0;
+ dbg->de_sect_sa_next_to_return = 0;
+}
+
+/*
+ Storage handler. Gets either a new chunk of memory, or
+ a pointer in existing memory, from the linked list attached
+ to dbg at de_debug_sects, depending on size of nbytes
+
+ Assume dbg not null, checked in top level routine
+
+ Returns a pointer to the allocated buffer space for the
+ lib to fill in, predincrements next-to-use count so the
+ space requested is already counted 'used'
+ when this returns (ie, reserved).
+
+*/
+Dwarf_Small *
+_dwarf_pro_buffer(Dwarf_P_Debug dbg,
+ int elfsectno, unsigned long nbytes)
+{
+ Dwarf_P_Section_Data cursect;
+
+
+ cursect = dbg->de_current_active_section;
+ /* By using MAGIC_SECT_NO we allow the following MAGIC_SECT_NO must
+ not match any legit section number. test to have just two
+ clauses (no NULL pointer test) See dwarf_producer_init(). */
+ if ((cursect->ds_elf_sect_no != elfsectno) ||
+ ((cursect->ds_nbytes + nbytes) > cursect->ds_orig_alloc)
+ ) {
+
+ /* Either the elf section has changed or there is not enough
+ space in the current section.
+
+ Create a new Dwarf_P_Section_Data_s for the chunk. and have
+ space 'on the end' for the buffer itself so we just do one
+ malloc (not two).
+
+ */
+ unsigned long space = nbytes;
+
+ if (nbytes < CHUNK_SIZE)
+ space = CHUNK_SIZE;
+
+ cursect = (Dwarf_P_Section_Data)
+ _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_Section_Data_s)
+ + space);
+
+
+ if (cursect == NULL)
+ return (NULL);
+
+ /* _dwarf_p_get_alloc zeroes the space... */
+
+ cursect->ds_data = (char *) cursect +
+ sizeof(struct Dwarf_P_Section_Data_s);
+ cursect->ds_orig_alloc = space;
+ cursect->ds_elf_sect_no = elfsectno;
+ cursect->ds_nbytes = nbytes; /* reserve this number of bytes
+ of space for caller to fill
+ in */
+
+ /* Now link on the end of the list, and mark this one as the
+ current one */
+
+ if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) {
+ /* the only entry is the special one for 'no entry' so
+ delete that phony one while adding this initial real
+ one. */
+ dbg->de_debug_sects = cursect;
+ dbg->de_current_active_section = cursect;
+ dbg->de_first_debug_sect = cursect;
+ } else {
+ dbg->de_current_active_section->ds_next = cursect;
+ dbg->de_current_active_section = cursect;
+ }
+ dbg->de_n_debug_sect++;
+
+ return ((Dwarf_Small *) cursect->ds_data);
+ }
+
+ /* There is enough space in the current buffer */
+ {
+ Dwarf_Small *space_for_caller = (Dwarf_Small *)
+ (cursect->ds_data + cursect->ds_nbytes);
+
+ cursect->ds_nbytes += nbytes;
+ return space_for_caller;
+ }
+}
+
+
+/*------------------------------------------------------------
+ Given address advance and line advance, it gives
+ either special opcode, or a number < 0
+------------------------------------------------------------*/
+static int
+_dwarf_pro_get_opc(Dwarf_Unsigned addr_adv, int line_adv)
+{
+ int opc;
+
+ addr_adv = addr_adv / MIN_INST_LENGTH;
+ if (line_adv == 0 && addr_adv == 0)
+ return OPC_INCS_ZERO;
+ if (line_adv >= LINE_BASE && line_adv < LINE_BASE + LINE_RANGE) {
+ opc =
+ (line_adv - LINE_BASE) + (addr_adv * LINE_RANGE) +
+ OPCODE_BASE;
+ if (opc > 255)
+ return OPC_OUT_OF_RANGE;
+ return opc;
+ } else
+ return LINE_OUT_OF_RANGE;
+}
+
+/*-----------------------------------------------------------------------
+ Handles abbreviations. It takes a die, searches through
+ current list of abbreviations for matching one. If it
+ finds one, it returns a pointer to it, and if it doesnt,
+ it returns a new one. Upto the user of this function to
+ link it up to the abbreviation head. If its a new one,
+ abb_idx has 0.
+-----------------------------------------------------------------------*/
+static Dwarf_P_Abbrev
+_dwarf_pro_getabbrev(Dwarf_P_Die die, Dwarf_P_Abbrev head)
+{
+ Dwarf_P_Abbrev curabbrev;
+ Dwarf_P_Attribute curattr;
+ int res1;
+ int nattrs;
+ int match;
+ Dwarf_ufixed *forms = 0;
+ Dwarf_ufixed *attrs = 0;
+
+ curabbrev = head;
+ while (curabbrev) {
+ if ((die->di_tag == curabbrev->abb_tag) &&
+ ((die->di_child != NULL &&
+ curabbrev->abb_children == DW_CHILDREN_yes) ||
+ (die->di_child == NULL &&
+ curabbrev->abb_children == DW_CHILDREN_no)) &&
+ (die->di_n_attr == curabbrev->abb_n_attr)) {
+
+ /* There is a chance of a match. */
+ curattr = die->di_attrs;
+ match = 1; /* Assume match found. */
+ while (match && curattr) {
+ res1 = _dwarf_pro_match_attr(curattr,
+ curabbrev,
+ (int) curabbrev->
+ abb_n_attr);
+ if (res1 == 0)
+ match = 0;
+ curattr = curattr->ar_next;
+ }
+ if (match == 1)
+ return curabbrev;
+ }
+ curabbrev = curabbrev->abb_next;
+ }
+
+ /* no match, create new abbreviation */
+ if (die->di_n_attr != 0) {
+ forms = (Dwarf_ufixed *)
+ _dwarf_p_get_alloc(die->di_dbg,
+ sizeof(Dwarf_ufixed) * die->di_n_attr);
+ if (forms == NULL)
+ return NULL;
+ attrs = (Dwarf_ufixed *)
+ _dwarf_p_get_alloc(die->di_dbg,
+ sizeof(Dwarf_ufixed) * die->di_n_attr);
+ if (attrs == NULL)
+ return NULL;
+ }
+ nattrs = 0;
+ curattr = die->di_attrs;
+ while (curattr) {
+ attrs[nattrs] = curattr->ar_attribute;
+ forms[nattrs] = curattr->ar_attribute_form;
+ nattrs++;
+ curattr = curattr->ar_next;
+ }
+
+ curabbrev = (Dwarf_P_Abbrev)
+ _dwarf_p_get_alloc(die->di_dbg, sizeof(struct Dwarf_P_Abbrev_s));
+ if (curabbrev == NULL)
+ return NULL;
+
+ if (die->di_child == NULL)
+ curabbrev->abb_children = DW_CHILDREN_no;
+ else
+ curabbrev->abb_children = DW_CHILDREN_yes;
+ curabbrev->abb_tag = die->di_tag;
+ curabbrev->abb_attrs = attrs;
+ curabbrev->abb_forms = forms;
+ curabbrev->abb_n_attr = die->di_n_attr;
+ curabbrev->abb_idx = 0;
+ curabbrev->abb_next = NULL;
+
+ return curabbrev;
+}
+
+/*------------------------------------------------------------------
+ Tries to see if given attribute and form combination
+ exists in the given abbreviation
+-------------------------------------------------------------------*/
+static int
+_dwarf_pro_match_attr(Dwarf_P_Attribute attr,
+ Dwarf_P_Abbrev abbrev, int no_attr)
+{
+ int i;
+ int found = 0;
+
+ for (i = 0; i < no_attr; i++) {
+ if (attr->ar_attribute == abbrev->abb_attrs[i] &&
+ attr->ar_attribute_form == abbrev->abb_forms[i]) {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_section.h b/usr/src/lib/libdwarf/common/pro_section.h
new file mode 100644
index 0000000000..b37ade44dc
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_section.h
@@ -0,0 +1,112 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+
+/* relocation section names */
+extern char *_dwarf_rel_section_names[];
+
+/* section names */
+extern char *_dwarf_sectnames[];
+
+/* struct to hold relocation entries. Its mantained as a linked
+ list of relocation structs, and will then be written at as a
+ whole into the relocation section. Whether its 32 bit or
+ 64 bit will be obtained from Dwarf_Debug pointer.
+*/
+
+
+
+
+
+/*
+ struct stores a chunk of data pertaining to a section
+*/
+struct Dwarf_P_Section_Data_s {
+ int ds_elf_sect_no; /* elf section number */
+ char *ds_data; /* data contained in section */
+ unsigned long ds_nbytes; /* bytes of data used so far */
+ unsigned long ds_orig_alloc; /* bytes allocated originally */
+ Dwarf_P_Section_Data ds_next; /* next on the list */
+};
+
+/* Used to allow a dummy initial struct (which we
+ drop before it gets used
+ This must not match any legitimate 'section' number.
+*/
+#define MAGIC_SECT_NO -3
+
+/* Size of chunk of data allocated in one alloc
+ Not clear if this is the best size.
+ Used to be just 4096 for user data, the section data struct
+ was a separate malloc.
+*/
+#define CHUNK_SIZE (4096 - sizeof (struct Dwarf_P_Section_Data_s))
+
+/*
+ chunk alloc routine -
+ if chunk->ds_data is nil, it will alloc CHUNK_SIZE bytes,
+ and return pointer to the beginning. If chunk is not nil,
+ it will see if there's enoungh space for nbytes in current
+ chunk, if not, add new chunk to linked list, and return
+ a char * pointer to it. Return null if unsuccessful.
+*/
+Dwarf_Small *_dwarf_pro_buffer(Dwarf_P_Debug dbg, int sectno,
+ unsigned long nbytes);
+
+#define GET_CHUNK(dbg,sectno,ptr,nbytes,error) \
+ { \
+ (ptr) = _dwarf_pro_buffer((dbg),(sectno),(nbytes)); \
+ if ((ptr) == NULL) { \
+ DWARF_P_DBG_ERROR(dbg,DW_DLE_CHUNK_ALLOC,-1); \
+ } \
+ }
+
+
+
+int
+ _dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+
+/* These are for creating ELF section type codes.
+*/
+#if defined(linux) || defined(__BEOS__) || !defined(SHT_MIPS_DWARF)
+/* Intel's SoftSdv accepts only this */
+#define SECTION_TYPE SHT_PROGBITS
+#else
+#define SECTION_TYPE SHT_MIPS_DWARF
+#endif
diff --git a/usr/src/lib/libdwarf/common/pro_types.c b/usr/src/lib/libdwarf/common/pro_types.c
new file mode 100644
index 0000000000..1f3f93280c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_types.c
@@ -0,0 +1,296 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+
+/*
+ This function adds another type name to the
+ list of type names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_typename(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *type_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, type_name,
+ dwarf_snk_typename, error);
+}
+
+/*
+ The following is the generic 'add a simple name entry'
+ for any of the simple name sections.
+
+ See enum dwarf_sn_kind in pro_opaque.h
+
+*/
+Dwarf_Unsigned
+_dwarf_add_simple_name_entry(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *entry_name,
+ enum dwarf_sn_kind entrykind,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Simple_nameentry nameentry;
+ Dwarf_P_Simple_name_header hdr;
+ char *name;
+ int uword_size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (0);
+ }
+
+ if (die == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return (0);
+ }
+
+
+ nameentry = (Dwarf_P_Simple_nameentry)
+ _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_Simple_nameentry_s));
+ if (nameentry == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ name = _dwarf_p_get_alloc(dbg, strlen(entry_name) + 1);
+ if (name == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ strcpy(name, entry_name);
+
+ nameentry->sne_die = die;
+ nameentry->sne_name = name;
+ nameentry->sne_name_len = strlen(name);
+ uword_size = dbg->de_offset_size;
+
+ hdr = &dbg->de_simple_name_headers[entrykind];
+ if (hdr->sn_head == NULL)
+ hdr->sn_head = hdr->sn_tail = nameentry;
+ else {
+ hdr->sn_tail->sne_next = nameentry;
+ hdr->sn_tail = nameentry;
+ }
+ hdr->sn_count++;
+ hdr->sn_net_len += uword_size + nameentry->sne_name_len + 1;
+
+ return (1);
+}
+
+
+
+/*
+ _dwarf_transform_simplename_to_disk writes
+ ".rel.debug_pubnames",
+ ".rel.debug_funcnames", sgi extension
+ ".rel.debug_typenames", sgi extension
+ ".rel.debug_varnames", sgi extension
+ ".rel.debug_weaknames", sgi extension
+ to disk.
+ section_index indexes one of those sections.
+ entrykind is one of those 'kind's.
+
+*/
+int
+_dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, enum dwarf_sn_kind entrykind, int section_index, /* in
+ de_elf_sects
+ etc
+ */
+ Dwarf_Error * error)
+{
+
+
+ /* Used to fill in 0. */
+ const Dwarf_Signed big_zero = 0;
+
+ /* Used to scan the section data buffers. */
+ Dwarf_P_Section_Data debug_sect;
+
+ Dwarf_Signed debug_info_size;
+
+ Dwarf_P_Simple_nameentry nameentry_original;
+ Dwarf_P_Simple_nameentry nameentry;
+ Dwarf_Small *stream_bytes;
+ Dwarf_Small *cur_stream_bytes_ptr;
+ Dwarf_Unsigned stream_bytes_count;
+ Dwarf_Unsigned adjusted_length; /* count excluding length field
+ */
+
+
+ int uword_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+
+ Dwarf_P_Simple_name_header hdr;
+
+
+ /* ***** BEGIN CODE ***** */
+
+ debug_info_size = 0;
+ for (debug_sect = dbg->de_debug_sects; debug_sect != NULL;
+ debug_sect = debug_sect->ds_next) {
+ /* We want the size of the .debug_info section for this CU
+ because the dwarf spec requires us to output it below so we
+ look for it specifically. */
+ if (debug_sect->ds_elf_sect_no == dbg->de_elf_sects[DEBUG_INFO]) {
+ debug_info_size += debug_sect->ds_nbytes;
+ }
+ }
+
+ hdr = &dbg->de_simple_name_headers[entrykind];
+ /* Size of the .debug_typenames (or similar) section header. */
+ stream_bytes_count = extension_size + uword_size + /* Size of
+ length
+ field. */
+ sizeof(Dwarf_Half) + /* Size of version field. */
+ uword_size + /* Size of .debug_info offset. */
+ uword_size; /* Size of .debug_names. */
+
+
+
+ nameentry_original = hdr->sn_head;
+ nameentry = nameentry_original;
+ /* add in the content size */
+ stream_bytes_count += hdr->sn_net_len;
+
+ /* Size of the last 0 offset. */
+ stream_bytes_count += uword_size;
+
+ /* Now we know how long the entire section is */
+ GET_CHUNK(dbg, dbg->de_elf_sects[section_index],
+ stream_bytes, (unsigned long) stream_bytes_count, error);
+ if (stream_bytes == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ cur_stream_bytes_ptr = stream_bytes;
+
+ if (extension_size) {
+ Dwarf_Unsigned x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &x, sizeof(x), extension_size);
+ cur_stream_bytes_ptr += extension_size;
+
+ }
+ /* Write the adjusted length of .debug_*names section. */
+ adjusted_length = stream_bytes_count - uword_size - extension_size;
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &adjusted_length,
+ sizeof(adjusted_length), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* Write the version as 2 bytes. */
+ {
+ Dwarf_Half verstamp = CURRENT_VERSION_STAMP;
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &verstamp,
+ sizeof(verstamp), sizeof(Dwarf_Half));
+ cur_stream_bytes_ptr += sizeof(Dwarf_Half);
+ }
+
+ /* Write the offset of the compile-unit. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* now create the relocation for the compile_unit offset */
+ {
+ int res = dbg->de_reloc_name(dbg,
+ section_index,
+ extension_size + uword_size +
+ sizeof(Dwarf_Half)
+ /* r_offset */
+ ,
+ /* debug_info section name symbol */
+ dbg->de_sect_name_idx[DEBUG_INFO],
+ dwarf_drt_data_reloc,
+ uword_size);
+
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+ }
+
+ /* Write the size of .debug_info section. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &debug_info_size,
+ sizeof(debug_info_size), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+
+ for (nameentry = nameentry_original;
+ nameentry != NULL; nameentry = nameentry->sne_next) {
+
+ /* Copy offset of die from start of compile-unit. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &nameentry->sne_die->di_offset,
+ sizeof(nameentry->sne_die->di_offset),
+ uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* Copy the type name. */
+ strcpy((char *) cur_stream_bytes_ptr, nameentry->sne_name);
+ cur_stream_bytes_ptr += nameentry->sne_name_len + 1;
+ }
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+
+
+
+
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_types.h b/usr/src/lib/libdwarf/common/pro_types.h
new file mode 100644
index 0000000000..817609215b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_types.h
@@ -0,0 +1,44 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+/* pro_types.h */
+
+
+int _dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, enum dwarf_sn_kind entrykind, int section_index, /* in
+ de_elf_sects
+ etc
+ */
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_util.h b/usr/src/lib/libdwarf/common/pro_util.h
new file mode 100644
index 0000000000..56bde8bda6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_util.h
@@ -0,0 +1,148 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+
+#define IS_64BIT(dbg) ((dbg)->de_flags & DW_DLC_SIZE_64 ? 1 : 0)
+#define ISA_IA64(dbg) ((dbg)->de_flags & DW_DLC_ISA_IA64 ? 1 : 0)
+
+/* definition of sizes of types, given target machine */
+#define sizeof_sbyte(dbg) sizeof(Dwarf_Sbyte)
+#define sizeof_ubyte(dbg) sizeof(Dwarf_Ubyte)
+#define sizeof_uhalf(dbg) sizeof(Dwarf_Half)
+/* certain sizes not defined here, but set in dbg record.
+ See pro_init.c
+*/
+
+/* Computes amount of padding necessary to align n to a k-boundary. */
+/* Important: Assumes n, k both GREATER than zero. */
+#define PADDING(n, k) ( (k)-1 - ((n)-1)%(k) )
+
+/* The following defines are only important for users of the
+** producer part of libdwarf, and such should have these
+** defined correctly (as necessary)
+** by the #include <elf.h> done in pro_incl.h
+** before the #include "pro_util.h".
+** For others producer macros do not matter so 0 is a usable value, and
+** zero values let compilation succeed on more non-MIPS architectures.
+** A better approach would be welcome.
+*/
+/* R_MIPS* are #define so #ifndef works */
+/* R_IA_64* are not necessarily #define (might be enum) so #ifndef
+ is useless, we use the configure script generating
+ HAVE_R_IA_64_DIR32LSB and HAVE_R_IA64_DIR32LSB.
+*/
+#ifndef R_MIPS_64
+#define R_MIPS_64 0
+#endif
+#ifndef R_MIPS_32
+#define R_MIPS_32 0
+#endif
+#ifndef R_MIPS_SCN_DISP
+#define R_MIPS_SCN_DISP 0
+#endif
+
+/* R_IA_64_DIR32LSB came before the now-standard R_IA64_DIR32LSB
+ (etc) was defined. This now deals with either form,
+ preferring the new form if available. */
+#ifdef HAVE_R_IA64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR32LSB R_IA64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR64LSB R_IA64_DIR64LSB
+#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA64_SEGREL64LSB
+#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA64_SEGREL32LSB
+#endif
+#if defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB)
+#define DWARF_PRO_R_IA64_DIR32LSB R_IA_64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR64LSB R_IA_64_DIR64LSB
+#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA_64_SEGREL64LSB
+#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA_64_SEGREL32LSB
+#endif
+#if !defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB)
+#define DWARF_PRO_R_IA64_DIR32LSB 0
+#define DWARF_PRO_R_IA64_DIR64LSB 0
+#define DWARF_PRO_R_IA64_SEGREL64LSB 0
+#define DWARF_PRO_R_IA64_SEGREL32LSB 0
+#endif
+
+/*
+ * The default "I don't know" value can't be zero.
+ * Because that's the sentinel value that means "no relocation".
+ * In order to use this library in 'symbolic relocation mode we
+ * don't care if this value is the right relocation value,
+ * only that it's non-NULL. So at the end, we define it
+ * to something sensible.
+ */
+
+
+
+#if defined(sun)
+#if defined(sparc)
+#define Get_REL64_isa(dbg) (R_SPARC_UA64)
+#define Get_REL32_isa(dbg) (R_SPARC_UA32)
+#define Get_REL_SEGREL_isa(dbg) (R_SPARC_NONE) /* I don't know! */
+#else /* i386 */
+#define Get_REL64_isa(dbg) (R_386_32) /* Any non-zero value is ok */
+#define Get_REL32_isa(dbg) (R_386_32)
+#define Get_REL_SEGREL_isa(dbg) (R_386_NONE) /* I don't know! */
+#endif /* sparc || i386 */
+#else /* !sun */
+#ifdef HAVE_SYS_IA64_ELF_H
+#define Get_REL64_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_DIR64LSB : R_MIPS_64)
+#define Get_REL32_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_DIR32LSB : R_MIPS_32)
+
+
+/* ia64 uses 32bit dwarf offsets for sections */
+#define Get_REL_SEGREL_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_SEGREL32LSB : R_MIPS_SCN_DISP)
+#else /* HAVE_SYS_IA64_ELF_H */
+
+#if !defined(linux) && !defined(__BEOS__)
+#define Get_REL64_isa(dbg) (R_MIPS_64)
+#define Get_REL32_isa(dbg) (R_MIPS_32)
+#define Get_REL_SEGREL_isa(dbg) (R_MIPS_SCN_DISP)
+#else
+#define Get_REL64_isa(dbg) (1)
+#define Get_REL32_isa(dbg) (1) /* these are used on linux */
+#define Get_REL_SEGREL_isa(dbg) (1) /* non zero values, see comments above */
+#endif
+
+#endif /* HAVE_SYS_IA64_ELF_H */
+#endif /* !sun */
+
+
diff --git a/usr/src/lib/libdwarf/common/pro_vars.c b/usr/src/lib/libdwarf/common/pro_vars.c
new file mode 100644
index 0000000000..3e75a9d9af
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_vars.c
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another variable name to the
+ list of variable names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_varname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die, char *var_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, var_name,
+ dwarf_snk_varname, error);
+
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_weaks.c b/usr/src/lib/libdwarf/common/pro_weaks.c
new file mode 100644
index 0000000000..8c74bf08ca
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_weaks.c
@@ -0,0 +1,61 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2.1 of the GNU Lesser General Public License
+ as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it would be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ Further, this software is distributed without any warranty that it is
+ free of the rightful claim of any third person regarding infringement
+ or the like. Any license provided herein, whether implied or
+ otherwise, applies only to this software file. Patent licenses, if
+ any, provided herein do not apply to combinations of this program with
+ other software, or any other product whatsoever.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, write the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another weak name to the
+ list of weak names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_weakname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *weak_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, weak_name,
+ dwarf_snk_weakname, error);
+}
diff --git a/usr/src/lib/libdwarf/i386/Makefile b/usr/src/lib/libdwarf/i386/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/libdwarf/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libdwarf/sparc/Makefile b/usr/src/lib/libdwarf/sparc/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/libdwarf/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libdwarf/sparcv9/Makefile b/usr/src/lib/libdwarf/sparcv9/Makefile
new file mode 100644
index 0000000000..4e7833710f
--- /dev/null
+++ b/usr/src/lib/libdwarf/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libgrubmgmt/common/libgrub_fs.c b/usr/src/lib/libgrubmgmt/common/libgrub_fs.c
index aa5faa6470..92078bccee 100644
--- a/usr/src/lib/libgrubmgmt/common/libgrub_fs.c
+++ b/usr/src/lib/libgrubmgmt/common/libgrub_fs.c
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2011 Joyent, Inc. All rights reserved.
*/
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
diff --git a/usr/src/lib/libidspace/Makefile b/usr/src/lib/libidspace/Makefile
new file mode 100644
index 0000000000..44640eeddc
--- /dev/null
+++ b/usr/src/lib/libidspace/Makefile
@@ -0,0 +1,45 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+HDRS = libidspace.h
+HDRDIR = common
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libidspace/Makefile.com b/usr/src/lib/libidspace/Makefile.com
new file mode 100644
index 0000000000..8cc60ffc4c
--- /dev/null
+++ b/usr/src/lib/libidspace/Makefile.com
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+LIBRARY = libidspace.a
+VERS = .1
+OBJECTS = id_space.o \
+ libidspace.o
+COMDIR = $(SRC)/common/idspace
+
+include ../../Makefile.lib
+
+SRCDIR = ../common
+SRCS = ../../../common/idspace/id_space.c
+LIBS = $(DYNLIB) $(LINTLIB)
+
+LDLIBS += -lc -lumem
+
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
+
+objs/%.o pics/%.o: $(COMDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libidspace/amd64/Makefile b/usr/src/lib/libidspace/amd64/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/libidspace/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libidspace/common/libidspace.c b/usr/src/lib/libidspace/common/libidspace.c
new file mode 100644
index 0000000000..7a9f8acd67
--- /dev/null
+++ b/usr/src/lib/libidspace/common/libidspace.c
@@ -0,0 +1,25 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ */
+
+/*
+ * Wrappers around the common id_space code, for userland.
+ */
+#include <sys/id_space.h>
+
+id_t
+id_alloc_specific(id_space_t *idp, id_t id)
+{
+ return (id_alloc_specific_nosleep(idp, id));
+}
diff --git a/usr/src/lib/libidspace/common/libidspace.h b/usr/src/lib/libidspace/common/libidspace.h
new file mode 100644
index 0000000000..bb8690f19c
--- /dev/null
+++ b/usr/src/lib/libidspace/common/libidspace.h
@@ -0,0 +1,42 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LIBIDSPACE_H
+#define _LIBIDSPACE_H
+
+/*
+ * libidspace public header
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+typedef struct id_space id_space_t;
+
+extern id_space_t *id_space_create(const char *, id_t, id_t);
+extern void id_space_destroy(id_space_t *);
+extern void id_space_extend(id_space_t *, id_t, id_t);
+extern id_t id_alloc(id_space_t *);
+extern id_t id_alloc_specific(id_space_t *, id_t);
+extern void id_free(id_space_t *, id_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBIDSPACE_H */
diff --git a/usr/src/lib/libidspace/common/llib-lidspace b/usr/src/lib/libidspace/common/llib-lidspace
new file mode 100644
index 0000000000..39c628da47
--- /dev/null
+++ b/usr/src/lib/libidspace/common/llib-lidspace
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libidspace.h>
diff --git a/usr/src/lib/libidspace/common/mapfile-vers b/usr/src/lib/libidspace/common/mapfile-vers
new file mode 100644
index 0000000000..61ae855ee0
--- /dev/null
+++ b/usr/src/lib/libidspace/common/mapfile-vers
@@ -0,0 +1,47 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOS_1.0 { # first release of libidspace
+ global:
+ id_alloc;
+ id_alloc_specific;
+ id_free;
+ id_space_create;
+ id_space_destroy;
+ id_space_extend;
+};
+
+
+SYMBOL_VERSION ILLUMOSprivate {
+ local:
+ *;
+};
+
diff --git a/usr/src/lib/libidspace/i386/Makefile b/usr/src/lib/libidspace/i386/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/libidspace/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libidspace/sparc/Makefile b/usr/src/lib/libidspace/sparc/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/libidspace/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libidspace/sparcv9/Makefile b/usr/src/lib/libidspace/sparcv9/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/libidspace/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libinetutil/common/mapfile-vers b/usr/src/lib/libinetutil/common/mapfile-vers
index a26d988990..c86fdd956d 100644
--- a/usr/src/lib/libinetutil/common/mapfile-vers
+++ b/usr/src/lib/libinetutil/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2017 Joyent, Inc.
#
#
diff --git a/usr/src/lib/libipadm/common/libipadm.c b/usr/src/lib/libipadm/common/libipadm.c
index 527f735e17..58297eda6b 100644
--- a/usr/src/lib/libipadm/common/libipadm.c
+++ b/usr/src/lib/libipadm/common/libipadm.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
@@ -285,11 +286,19 @@ ipadm_close(ipadm_handle_t iph)
boolean_t
ipadm_check_auth(void)
{
+ int uid;
struct passwd pwd;
char buf[NSS_BUFLEN_PASSWD];
+ /*
+ * Branded zones may have different kinds of auth, but root always
+ * allowed.
+ */
+ if ((uid = getuid()) == 0)
+ return (B_TRUE);
+
/* get the password entry for the given user ID */
- if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
+ if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL)
return (B_FALSE);
/* check for presence of given authorization */
@@ -897,9 +906,21 @@ ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
reopen:
(void) pthread_mutex_lock(&iph->iph_lock);
- /* The door descriptor is opened if it isn't already */
+ /*
+ * The door descriptor is opened if it isn't already.
+ */
if (iph->iph_door_fd == -1) {
- if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
+ char door[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+
+ /*
+ * If this is a branded zone, make sure we use the "/native"
+ * prefix for the door path:
+ */
+ (void) snprintf(door, sizeof (door), "%s%s", zroot != NULL ?
+ zroot : "", IPMGMT_DOOR);
+
+ if ((iph->iph_door_fd = open(door, O_RDONLY)) < 0) {
err = errno;
(void) pthread_mutex_unlock(&iph->iph_lock);
return (err);
diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
index 9557d11286..72432160c7 100644
--- a/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
+++ b/usr/src/lib/libkmf/plugins/kmf_openssl/Makefile.com
@@ -37,8 +37,8 @@ KMFINC= -I../../../include -I../../../ber_der/inc
BERLIB= -lkmf -lkmfberder
BERLIB64= $(BERLIB)
-OPENSSLLIBS= $(BERLIB) -lcrypto -lcryptoutil -lc
-OPENSSLLIBS64= $(BERLIB64) -lcrypto -lcryptoutil -lc
+OPENSSLLIBS= $(BERLIB) -lsunw_crypto -lcryptoutil -lc
+OPENSSLLIBS64= $(BERLIB64) -lsunw_crypto -lcryptoutil -lc
LINTSSLLIBS = $(BERLIB) -lcrypto -lcryptoutil -lc
LINTSSLLIBS64 = $(BERLIB64) -lcrypto -lcryptoutil -lc
diff --git a/usr/src/lib/libnisdb/db_mindex3.cc b/usr/src/lib/libnisdb/db_mindex3.cc
index d3db240b3c..e70076f409 100644
--- a/usr/src/lib/libnisdb/db_mindex3.cc
+++ b/usr/src/lib/libnisdb/db_mindex3.cc
@@ -284,7 +284,7 @@ entriesFromLDAPthread(void *voidarg) {
/* Lock to prevent removal */
(void) __nis_lock_db_table(arg->tableName, 1, 0,
- "entriesFromLDAPthread");
+ (char *)"entriesFromLDAPthread");
/*
* It's possible that the db_mindex for the table has changed,
@@ -316,7 +316,7 @@ entriesFromLDAPthread(void *voidarg) {
(void) entriesFromLDAPreal(arg);
(void) __nis_ulock_db_table(arg->tableName, 1, 0,
- "entriesFromLDAPthread");
+ (char *)"entriesFromLDAPthread");
freeQuery(arg->q);
if (arg->dirObj != 0)
diff --git a/usr/src/lib/libnisdb/db_table.cc b/usr/src/lib/libnisdb/db_table.cc
index c7cbfafcaf..bbd83fcc01 100644
--- a/usr/src/lib/libnisdb/db_table.cc
+++ b/usr/src/lib/libnisdb/db_table.cc
@@ -602,7 +602,7 @@ db_table::setEntryExp(entryp where, entry_obj *obj, int initialLoad) {
if (o != 0) {
__nis_buffer_t b = {0, 0};
- bp2buf(myself, &b, "%s.%s",
+ bp2buf(myself, &b, (char *)"%s.%s",
o->zo_name, o->zo_domain);
t = getObjMapping(b.buf, 0, 1, 0, 0);
sfree(b.buf);
@@ -970,7 +970,7 @@ db_table::setEnumMode(long enumNum) {
if (stat != DB_SUCCESS) {
enumMode.flag = 0;
enumCount.flag = 0;
- logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ logmsg(MSG_NOTIMECHECK, LOG_ERR, (char *)
"%s: No memory for enum check array; entry removal disabled",
myself);
}
diff --git a/usr/src/lib/libnisdb/nis_db.cc b/usr/src/lib/libnisdb/nis_db.cc
index 1007a396bf..0aa1556c33 100644
--- a/usr/src/lib/libnisdb/nis_db.cc
+++ b/usr/src/lib/libnisdb/nis_db.cc
@@ -529,7 +529,7 @@ dbFindObject(char *objName, db_status *statP) {
/* If not the root dir, find the directory where the entry lives */
sfree(table);
- name = entryName(myself, objName, &table);
+ name = entryName((char *)myself, objName, &table);
if (name == 0 || table == 0) {
sfree(name);
RETSTAT(0, DB_MEMORY_LIMIT);
@@ -739,7 +739,7 @@ dbDeleteObj(char *objName) {
nod->objType = o->zo_data.zo_type;
nis_destroy_object(o);
- nod->objName = sdup(myself, T, objName);
+ nod->objName = sdup((char *)myself, T, objName);
if (nod->objName == 0) {
sfree(nod);
return (DB_MEMORY_LIMIT);
@@ -791,7 +791,7 @@ dbTouchObj(char *objName) {
sfree(table);
table = 0;
- ent = entryName(myself, objName, &table);
+ ent = entryName((char *)myself, objName, &table);
if (ent == 0 || table == 0) {
sfree(ent);
return (DB_MEMORY_LIMIT);
@@ -991,7 +991,7 @@ dbRefreshObj(char *name, nis_object *o) {
int lstat;
/* Find parent */
- ent = entryName(myself, objName, &table);
+ ent = entryName((char *)myself, objName, &table);
if (ent == 0 || table == 0) {
sfree(b.buf);
sfree(objTable);
diff --git a/usr/src/lib/libnsl/common/mapfile-vers b/usr/src/lib/libnsl/common/mapfile-vers
index 9a0b25a16b..aafb70af9f 100644
--- a/usr/src/lib/libnsl/common/mapfile-vers
+++ b/usr/src/lib/libnsl/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Joyent, Inc.
# Copyright 2017 Nexenta Systems, Inc. All rights reserved.
#
diff --git a/usr/src/lib/libnsl/netselect/netselect.c b/usr/src/lib/libnsl/netselect/netselect.c
index 41dfa4909a..7790894c9e 100644
--- a/usr/src/lib/libnsl/netselect/netselect.c
+++ b/usr/src/lib/libnsl/netselect/netselect.c
@@ -22,6 +22,7 @@
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -32,8 +33,6 @@
* under license from the Regents of the University of California.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "mt.h"
#include "../rpc/rpc_mt.h" /* for MT declarations only */
#include <rpc/types.h>
@@ -45,6 +44,7 @@
#include <malloc.h>
#include <libintl.h>
#include <syslog.h>
+#include <zone.h>
#include "netcspace.h"
#define FAILURE (unsigned)(-1)
@@ -265,13 +265,22 @@ freenetconfigent(struct netconfig *netp)
static struct netconfig **
getnetlist(void)
{
- char line[BUFSIZ]; /* holds each line of NETCONFIG */
- FILE *fp; /* file stream for NETCONFIG */
+ FILE *fp = NULL; /* file stream for NETCONFIG */
struct netconfig **listpp; /* the beginning of the netconfig list */
struct netconfig **tpp; /* used to traverse the netconfig list */
int count; /* the number of entries in file */
+ char nc_path[MAXPATHLEN];
+ const char *zroot = zone_get_nroot();
+ char line[BUFSIZ]; /* holds each line of NETCONFIG */
+
+ /*
+ * If we are running in a branded zone, ensure we use the "/native"
+ * prefix when opening the netconfig file:
+ */
+ (void) snprintf(nc_path, sizeof (nc_path), "%s%s", zroot != NULL ?
+ zroot : "", NETCONFIG);
- if ((fp = fopen(NETCONFIG, "rF")) == NULL) {
+ if ((fp = fopen(nc_path, "rF")) == NULL) {
nc_error = NC_OPENFAIL;
return (NULL);
}
@@ -286,13 +295,16 @@ getnetlist(void)
if (count == 0) {
nc_error = NC_NOTFOUND;
- (void) fclose(fp);
+ if (fp != NULL)
+ (void) fclose(fp);
return (NULL);
}
+
if ((listpp = malloc((count + 1) *
sizeof (struct netconfig *))) == NULL) {
nc_error = NC_NOMEM;
- (void) fclose(fp);
+ if (fp != NULL)
+ (void) fclose(fp);
return (NULL);
}
@@ -311,6 +323,7 @@ getnetlist(void)
if (nc_error != NC_NOMOREENTRIES) /* Something is screwed up */
netlist_free(&listpp);
+
return (listpp);
}
diff --git a/usr/src/lib/libnvpair/libnvpair.h b/usr/src/lib/libnvpair/libnvpair.h
index b05669e506..197ec37f46 100644
--- a/usr/src/lib/libnvpair/libnvpair.h
+++ b/usr/src/lib/libnvpair/libnvpair.h
@@ -49,6 +49,8 @@ extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
extern void nvlist_print(FILE *, nvlist_t *);
extern int nvlist_print_json(FILE *, nvlist_t *);
extern void dump_nvlist(nvlist_t *, int);
+extern int nvlist_dump_json(nvlist_t *, char **);
+extern void nvlist_dump_json_free(nvlist_t *, char *);
/*
* Private nvlist printing interface that allows the caller some control
diff --git a/usr/src/lib/libnvpair/mapfile-vers b/usr/src/lib/libnvpair/mapfile-vers
index 0403964e05..9b1f048f75 100644
--- a/usr/src/lib/libnvpair/mapfile-vers
+++ b/usr/src/lib/libnvpair/mapfile-vers
@@ -244,6 +244,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
dump_nvlist;
nvlist_add_hrtime;
nvlist_lookup_hrtime;
+ nvlist_dump_json;
+ nvlist_dump_json_free;
nvlist_print;
nvlist_print_json;
nvlist_prt;
diff --git a/usr/src/lib/libnvpair/nvpair_json.c b/usr/src/lib/libnvpair/nvpair_json.c
index 5a317f5f94..7ebd1be7a0 100644
--- a/usr/src/lib/libnvpair/nvpair_json.c
+++ b/usr/src/lib/libnvpair/nvpair_json.c
@@ -17,16 +17,71 @@
#include <strings.h>
#include <wchar.h>
#include <sys/debug.h>
+#include <stdarg.h>
+#include <assert.h>
#include "libnvpair.h"
-#define FPRINTF(fp, ...) \
+#define FPRINTF(bufp, blen, offp, ...) \
do { \
- if (fprintf(fp, __VA_ARGS__) < 0) \
+ if (nvlist_rasnprintf(bufp, blen, offp, \
+ __VA_ARGS__) < 0) \
return (-1); \
} while (0)
/*
+ * A realloc-aware snprintf/asprintf like function.
+ */
+/*PRINTFLIKE4*/
+static int
+nvlist_rasnprintf(char **bufp, size_t *blen, off_t *boff, char *input, ...)
+{
+ int ret;
+ va_list ap;
+ size_t size;
+ char *b;
+
+ if (*bufp == NULL) {
+ assert(*blen == 0);
+ assert(*boff == 0);
+ /* Pick a reasonable starting point, let's say 1k */
+ *blen = 1024;
+ *bufp = malloc(*blen);
+ if (*bufp == NULL)
+ return (-1);
+ }
+
+ size = *blen - *boff;
+ va_start(ap, input);
+ /* E_SEC_PRINTF_VAR_FMT */
+ ret = vsnprintf(*bufp + *boff, size, input, ap);
+ va_end(ap);
+ if (ret < 0)
+ return (-1);
+
+ if (ret >= size) {
+ size_t asize = *blen;
+ while (ret + *boff >= asize)
+ asize += 1024;
+ if ((b = realloc(*bufp, asize)) == NULL)
+ return (-1);
+ *bufp = b;
+ *blen = asize;
+ size = *blen - *boff;
+ va_start(ap, input);
+ /* E_SEC_PRINTF_VAR_FMT */
+ ret = vsnprintf(*bufp + *boff, size, input, ap);
+ va_end(ap);
+ if (ret < 0)
+ return (-1);
+ assert(ret < size);
+ }
+ *boff += ret;
+
+ return (0);
+}
+
+/*
* When formatting a string for JSON output we must escape certain characters,
* as described in RFC4627. This applies to both member names and
* DATA_TYPE_STRING values.
@@ -43,7 +98,8 @@
* representable Unicode characters included in their escaped numeric form.
*/
static int
-nvlist_print_json_string(FILE *fp, const char *input)
+nvlist_print_json_string(const char *input, char **bufp, size_t *blen,
+ off_t *offp)
{
mbstate_t mbr;
wchar_t c;
@@ -51,29 +107,29 @@ nvlist_print_json_string(FILE *fp, const char *input)
bzero(&mbr, sizeof (mbr));
- FPRINTF(fp, "\"");
+ FPRINTF(bufp, blen, offp, "\"");
while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
switch (c) {
case '"':
- FPRINTF(fp, "\\\"");
+ FPRINTF(bufp, blen, offp, "\\\"");
break;
case '\n':
- FPRINTF(fp, "\\n");
+ FPRINTF(bufp, blen, offp, "\\n");
break;
case '\r':
- FPRINTF(fp, "\\r");
+ FPRINTF(bufp, blen, offp, "\\r");
break;
case '\\':
- FPRINTF(fp, "\\\\");
+ FPRINTF(bufp, blen, offp, "\\\\");
break;
case '\f':
- FPRINTF(fp, "\\f");
+ FPRINTF(bufp, blen, offp, "\\f");
break;
case '\t':
- FPRINTF(fp, "\\t");
+ FPRINTF(bufp, blen, offp, "\\t");
break;
case '\b':
- FPRINTF(fp, "\\b");
+ FPRINTF(bufp, blen, offp, "\\b");
break;
default:
if ((c >= 0x00 && c <= 0x1f) ||
@@ -83,13 +139,15 @@ nvlist_print_json_string(FILE *fp, const char *input)
* characters in the Basic Multilingual Plane
* as JSON-escaped multibyte characters.
*/
- FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
+ FPRINTF(bufp, blen, offp, "\\u%04x",
+ (int)(0xffff & c));
} else if (c >= 0x20 && c <= 0x7f) {
/*
* Render other 7-bit ASCII characters directly
* and drop other, unrepresentable characters.
*/
- FPRINTF(fp, "%c", (int)(0xff & c));
+ FPRINTF(bufp, blen, offp, "%c",
+ (int)(0xff & c));
}
break;
}
@@ -104,98 +162,103 @@ nvlist_print_json_string(FILE *fp, const char *input)
return (-1);
}
- FPRINTF(fp, "\"");
+ FPRINTF(bufp, blen, offp, "\"");
return (0);
}
-/*
- * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
- * This routine does not output any new-lines or additional whitespace other
- * than that contained in strings, nor does it call fflush(3C).
- */
-int
-nvlist_print_json(FILE *fp, nvlist_t *nvl)
+static int
+nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
{
nvpair_t *curr;
boolean_t first = B_TRUE;
- FPRINTF(fp, "{");
+ FPRINTF(bufp, blen, offp, "{");
for (curr = nvlist_next_nvpair(nvl, NULL); curr;
curr = nvlist_next_nvpair(nvl, curr)) {
data_type_t type = nvpair_type(curr);
if (!first)
- FPRINTF(fp, ",");
+ FPRINTF(bufp, blen, offp, ",");
else
first = B_FALSE;
- if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
+ if (nvlist_print_json_string(nvpair_name(curr), bufp, blen,
+ offp) == -1)
return (-1);
- FPRINTF(fp, ":");
+ FPRINTF(bufp, blen, offp, ":");
switch (type) {
case DATA_TYPE_STRING: {
char *string = fnvpair_value_string(curr);
- if (nvlist_print_json_string(fp, string) == -1)
+ if (nvlist_print_json_string(string, bufp, blen,
+ offp) == -1)
return (-1);
break;
}
case DATA_TYPE_BOOLEAN: {
- FPRINTF(fp, "true");
+ FPRINTF(bufp, blen, offp, "true");
break;
}
case DATA_TYPE_BOOLEAN_VALUE: {
- FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
- B_TRUE ? "true" : "false");
+ FPRINTF(bufp, blen, offp, "%s",
+ fnvpair_value_boolean_value(curr) == B_TRUE ?
+ "true" : "false");
break;
}
case DATA_TYPE_BYTE: {
- FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
+ FPRINTF(bufp, blen, offp, "%hhu",
+ fnvpair_value_byte(curr));
break;
}
case DATA_TYPE_INT8: {
- FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
+ FPRINTF(bufp, blen, offp, "%hhd",
+ fnvpair_value_int8(curr));
break;
}
case DATA_TYPE_UINT8: {
- FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
+ FPRINTF(bufp, blen, offp, "%hhu",
+ fnvpair_value_uint8_t(curr));
break;
}
case DATA_TYPE_INT16: {
- FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
+ FPRINTF(bufp, blen, offp, "%hd",
+ fnvpair_value_int16(curr));
break;
}
case DATA_TYPE_UINT16: {
- FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
+ FPRINTF(bufp, blen, offp, "%hu",
+ fnvpair_value_uint16(curr));
break;
}
case DATA_TYPE_INT32: {
- FPRINTF(fp, "%d", fnvpair_value_int32(curr));
+ FPRINTF(bufp, blen, offp, "%d",
+ fnvpair_value_int32(curr));
break;
}
case DATA_TYPE_UINT32: {
- FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
+ FPRINTF(bufp, blen, offp, "%u",
+ fnvpair_value_uint32(curr));
break;
}
case DATA_TYPE_INT64: {
- FPRINTF(fp, "%lld",
+ FPRINTF(bufp, blen, offp, "%lld",
(long long)fnvpair_value_int64(curr));
break;
}
case DATA_TYPE_UINT64: {
- FPRINTF(fp, "%llu",
+ FPRINTF(bufp, blen, offp, "%llu",
(unsigned long long)fnvpair_value_uint64(curr));
break;
}
@@ -203,20 +266,21 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
case DATA_TYPE_HRTIME: {
hrtime_t val;
VERIFY0(nvpair_value_hrtime(curr, &val));
- FPRINTF(fp, "%llu", (unsigned long long)val);
+ FPRINTF(bufp, blen, offp, "%llu",
+ (unsigned long long)val);
break;
}
case DATA_TYPE_DOUBLE: {
double val;
VERIFY0(nvpair_value_double(curr, &val));
- FPRINTF(fp, "%f", val);
+ FPRINTF(bufp, blen, offp, "%f", val);
break;
}
case DATA_TYPE_NVLIST: {
- if (nvlist_print_json(fp,
- fnvpair_value_nvlist(curr)) == -1)
+ if (nvlist_do_json(fnvpair_value_nvlist(curr), bufp,
+ blen, offp) == -1)
return (-1);
break;
}
@@ -225,14 +289,15 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
char **val;
uint_t valsz, i;
VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- if (nvlist_print_json_string(fp, val[i]) == -1)
+ FPRINTF(bufp, blen, offp, ",");
+ if (nvlist_print_json_string(val[i], bufp,
+ blen, offp) == -1)
return (-1);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -240,14 +305,15 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
nvlist_t **val;
uint_t valsz, i;
VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- if (nvlist_print_json(fp, val[i]) == -1)
+ FPRINTF(bufp, blen, offp, ",");
+ if (nvlist_do_json(val[i], bufp, blen,
+ offp) == -1)
return (-1);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -255,14 +321,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
boolean_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, val[i] == B_TRUE ?
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, val[i] == B_TRUE ?
"true" : "false");
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -270,13 +336,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
uchar_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hhu", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%hhu", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -284,13 +350,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
uint8_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hhu", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%hhu", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -298,13 +364,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
int8_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hd", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%hd", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -312,13 +378,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
uint16_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hu", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%hu", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -326,13 +392,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
int16_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%hd", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%hd", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -340,13 +406,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
uint32_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%u", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%u", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -354,13 +420,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
int32_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%d", val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%d", val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -368,14 +434,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
uint64_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%llu",
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%llu",
(unsigned long long)val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -383,13 +449,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
int64_t *val;
uint_t valsz, i;
VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
- FPRINTF(fp, "[");
+ FPRINTF(bufp, blen, offp, "[");
for (i = 0; i < valsz; i++) {
if (i > 0)
- FPRINTF(fp, ",");
- FPRINTF(fp, "%lld", (long long)val[i]);
+ FPRINTF(bufp, blen, offp, ",");
+ FPRINTF(bufp, blen, offp, "%lld",
+ (long long)val[i]);
}
- FPRINTF(fp, "]");
+ FPRINTF(bufp, blen, offp, "]");
break;
}
@@ -398,6 +465,41 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)
}
}
- FPRINTF(fp, "}");
+ FPRINTF(bufp, blen, offp, "}");
return (0);
}
+
+int
+nvlist_dump_json(nvlist_t *nvl, char **bufp)
+{
+ off_t off = 0;
+ size_t l = 0;
+
+ *bufp = NULL;
+ return (nvlist_do_json(nvl, bufp, &l, &off));
+}
+
+/* ARGSUSED */
+void
+nvlist_dump_json_free(nvlist_t *nvl, char *buf)
+{
+ free(buf);
+}
+
+/*
+ * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
+ * This routine does not output any new-lines or additional whitespace other
+ * than that contained in strings, nor does it call fflush(3C).
+ */
+int
+nvlist_print_json(FILE *fp, nvlist_t *nvl)
+{
+ int ret;
+ char *buf;
+
+ if ((ret = nvlist_dump_json(nvl, &buf)) < 0)
+ return (ret);
+ ret = fprintf(fp, "%s", buf);
+ nvlist_dump_json_free(nvl, buf);
+ return (ret);
+}
diff --git a/usr/src/lib/libofmt/common/mapfile-vers b/usr/src/lib/libofmt/common/mapfile-vers
index b2a87b3ecc..fa94086eb6 100644
--- a/usr/src/lib/libofmt/common/mapfile-vers
+++ b/usr/src/lib/libofmt/common/mapfile-vers
@@ -11,6 +11,7 @@
#
# Copyright 2017 Nexenta Systems, Inc.
+# Copyright 2017 Joyent, Inc.
#
#
@@ -36,6 +37,7 @@ SYMBOL_VERSION ILLUMOSprivate {
ofmt_print;
ofmt_strerror;
ofmt_update_winsize;
+ ofmt_check;
local:
*;
diff --git a/usr/src/lib/libofmt/common/ofmt.c b/usr/src/lib/libofmt/common/ofmt.c
index bab3da7311..27765b0430 100644
--- a/usr/src/lib/libofmt/common/ofmt.c
+++ b/usr/src/lib/libofmt/common/ofmt.c
@@ -23,6 +23,11 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
#include <errno.h>
#include <sys/types.h>
#include <stdlib.h>
@@ -34,6 +39,7 @@
#include <unistd.h>
#include <sys/sysmacros.h>
#include <libintl.h>
+#include <assert.h>
/*
* functions and structures to internally process a comma-separated string
@@ -45,9 +51,8 @@ typedef struct {
uint_t s_nfields; /* the number of fields in s_buf */
uint_t s_currfield; /* the current field being processed */
} split_t;
+
static void splitfree(split_t *);
-static split_t *split_str(const char *, uint_t);
-static split_t *split_fields(const ofmt_field_t *, uint_t, uint_t);
/*
* The state of the output is tracked in a ofmt_state_t structure.
@@ -122,26 +127,30 @@ fail:
}
/*
- * Split `fields' into at most `maxfields' fields. Return a pointer to
- * a split_t containing the split fields, or NULL on failure. Invoked
- * when all fields are implicitly selected at handle creation by
- * passing in a NULL fields_str
+ * Split a template into its maximum number of fields (capped by the maxcols
+ * if it's non-zero). Return a pointer to a split_t containing the split
+ * fields, or NULL on failure. Invoked when all fields are implicitly
+ * selected at handle creation.
*/
static split_t *
-split_fields(const ofmt_field_t *template, uint_t maxfields, uint_t maxcols)
+split_max(const ofmt_field_t *template, uint_t maxcols)
{
+ const ofmt_field_t *ofp;
split_t *sp;
- int i, cols;
+ int i, cols, nfields = 0;
sp = calloc(sizeof (split_t), 1);
if (sp == NULL)
return (NULL);
- sp->s_fields = malloc(sizeof (char *) * maxfields);
+ for (ofp = template; ofp->of_name != NULL; ofp++)
+ nfields++;
+
+ sp->s_fields = malloc(sizeof (char *) * nfields);
if (sp->s_fields == NULL)
goto fail;
cols = 0;
- for (i = 0; i < maxfields; i++) {
+ for (i = 0; i < nfields; i++) {
cols += template[i].of_width;
/*
* If all fields are implied without explicitly passing
@@ -179,11 +188,10 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
uint_t maxcols, ofmt_handle_t *ofmt)
{
split_t *sp;
- uint_t i, j, of_index;
+ uint_t i, of_index;
const ofmt_field_t *ofp;
ofmt_field_t *of;
ofmt_state_t *os = NULL;
- int nfields = 0;
ofmt_status_t error = OFMT_SUCCESS;
boolean_t parsable = (flags & OFMT_PARSABLE);
boolean_t wrap = (flags & OFMT_WRAP);
@@ -207,18 +215,29 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
}
if (template == NULL)
return (OFMT_ENOTEMPLATE);
- for (ofp = template; ofp->of_name != NULL; ofp++)
- nfields++;
+
/*
* split str into the columns selected, or construct the
* full set of columns (equivalent to -o all).
*/
if (str != NULL && strcasecmp(str, "all") != 0) {
+ const char *c;
+ int nfields = 1;
+
+ /*
+ * Get an upper bound on the number of fields by counting
+ * the commas.
+ */
+ for (c = str; *c != '\0'; c++) {
+ if (*c == ',')
+ nfields++;
+ }
+
sp = split_str(str, nfields);
} else {
if (parsable || (str != NULL && strcasecmp(str, "all") == 0))
maxcols = 0;
- sp = split_fields(template, nfields, maxcols);
+ sp = split_max(template, maxcols);
}
if (sp == NULL)
goto nomem;
@@ -238,13 +257,12 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
* nfields is the number of fields in template.
*/
for (i = 0; i < sp->s_nfields; i++) {
- for (j = 0; j < nfields; j++) {
- if (strcasecmp(sp->s_fields[i],
- template[j].of_name) == 0) {
+ for (ofp = template; ofp->of_name != NULL; ofp++) {
+ if (strcasecmp(sp->s_fields[i], ofp->of_name) == 0)
break;
- }
}
- if (j == nfields) {
+
+ if (ofp->of_name == NULL) {
int nbad = os->os_nbad++;
error = OFMT_EBADFIELDS;
@@ -259,7 +277,7 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
goto nomem;
continue;
}
- of[of_index].of_name = strdup(template[j].of_name);
+ of[of_index].of_name = strdup(ofp->of_name);
if (of[of_index].of_name == NULL)
goto nomem;
if (multiline) {
@@ -267,9 +285,9 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
os->os_maxnamelen = MAX(n, os->os_maxnamelen);
}
- of[of_index].of_width = template[j].of_width;
- of[of_index].of_id = template[j].of_id;
- of[of_index].of_cb = template[j].of_cb;
+ of[of_index].of_width = ofp->of_width;
+ of[of_index].of_id = ofp->of_id;
+ of[of_index].of_cb = ofp->of_cb;
of_index++;
}
splitfree(sp);
@@ -612,3 +630,31 @@ ofmt_strerror(ofmt_handle_t ofmt, ofmt_status_t error, char *buf,
(void) strlcat(buf, ebuf, bufsize);
return (buf);
}
+
+void
+ofmt_check(ofmt_status_t oferr, boolean_t parsable, ofmt_handle_t ofmt,
+ void (*die)(const char *, ...), void (*warn)(const char *, ...))
+{
+ char buf[OFMT_BUFSIZE];
+
+ assert(die != NULL);
+ assert(warn != NULL);
+
+ if (oferr == OFMT_SUCCESS)
+ return;
+
+ (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
+
+ /*
+ * All errors are considered fatal in parsable mode. OFMT_ENOMEM and
+ * OFMT_ENOFIELDS errors are always fatal, regardless of mode. For
+ * other errors, we print diagnostics in human-readable mode and
+ * processs what we can.
+ */
+ if (parsable || oferr == OFMT_ENOFIELDS || oferr == OFMT_ENOMEM) {
+ ofmt_close(ofmt);
+ die(buf);
+ } else {
+ warn(buf);
+ }
+}
diff --git a/usr/src/lib/libofmt/common/ofmt.h b/usr/src/lib/libofmt/common/ofmt.h
index e69d43e20a..f2cf1ac682 100644
--- a/usr/src/lib/libofmt/common/ofmt.h
+++ b/usr/src/lib/libofmt/common/ofmt.h
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
#ifndef _OFMT_H
#define _OFMT_H
@@ -203,6 +207,10 @@ extern void ofmt_update_winsize(ofmt_handle_t);
*/
extern char *ofmt_strerror(ofmt_handle_t, ofmt_status_t, char *, uint_t);
+extern void ofmt_check(ofmt_status_t oferr, boolean_t parsable,
+ ofmt_handle_t ofmt,
+ void (*die)(const char *, ...), void (*warn)(const char *, ...));
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c
index 9af5026014..f18d4cefd8 100644
--- a/usr/src/lib/libproc/common/Pcontrol.c
+++ b/usr/src/lib/libproc/common/Pcontrol.c
@@ -347,10 +347,16 @@ static const ps_ops_t P_live_ops = {
void
_libproc_init(void)
{
+ const char *root;
+
_libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
_libproc_no_qsort = getenv("LIBPROC_NO_QSORT") != NULL;
_libproc_incore_elf = getenv("LIBPROC_INCORE_ELF") != NULL;
+ if ((root = zone_get_nroot()) != NULL)
+ (void) snprintf(procfs_path, sizeof (procfs_path), "%s/proc",
+ root);
+
(void) sigfillset(&blockable_sigs);
(void) sigdelset(&blockable_sigs, SIGKILL);
(void) sigdelset(&blockable_sigs, SIGSTOP);
@@ -1791,6 +1797,9 @@ prldump(const char *caller, lwpstatus_t *lsp)
case PR_SUSPENDED:
dprintf("%s: SUSPENDED\n", caller);
break;
+ case PR_BRAND:
+ dprintf("%s: BRANDPRIVATE (%d)\n", caller, lsp->pr_what);
+ break;
default:
dprintf("%s: Unknown\n", caller);
break;
@@ -1970,6 +1979,7 @@ Pstopstatus(struct ps_prochandle *P,
case PR_FAULTED:
case PR_JOBCONTROL:
case PR_SUSPENDED:
+ case PR_BRAND:
break;
default:
errno = EPROTO;
@@ -3544,6 +3554,7 @@ Lstopstatus(struct ps_lwphandle *L,
case PR_FAULTED:
case PR_JOBCONTROL:
case PR_SUSPENDED:
+ case PR_BRAND:
break;
default:
errno = EPROTO;
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
index ce5063f621..7e19e8777c 100644
--- a/usr/src/lib/libproc/common/Pcontrol.h
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -24,7 +24,7 @@
*/
/*
* Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
@@ -97,6 +97,7 @@ typedef struct file_info { /* symbol information for a mapped file */
struct map_info *file_map; /* primary (text) mapping */
int file_ref; /* references from map_info_t structures */
int file_fd; /* file descriptor for the mapped file */
+ int file_dbgfile; /* file descriptor for the debug file */
int file_init; /* 0: initialization yet to be performed */
GElf_Half file_etype; /* ELF e_type from ehdr */
GElf_Half file_class; /* ELF e_ident[EI_CLASS] from ehdr */
@@ -106,6 +107,7 @@ typedef struct file_info { /* symbol information for a mapped file */
char *file_rname; /* resolved on-disk object pathname */
char *file_rbase; /* pointer to basename of file_rname */
Elf *file_elf; /* ELF handle so we can close */
+ Elf *file_dbgelf; /* Debug ELF handle so we can close */
void *file_elfmem; /* data for faked-up ELF handle */
sym_tbl_t file_symtab; /* symbol table */
sym_tbl_t file_dynsym; /* dynamic symbol table */
@@ -122,6 +124,7 @@ typedef struct file_info { /* symbol information for a mapped file */
size_t file_shstrsz; /* section header string table size */
uintptr_t *file_saddrs; /* section header addresses */
uint_t file_nsaddrs; /* number of section header addresses */
+ boolean_t file_cvt; /* Have we tried to convert this? */
} file_info_t;
typedef struct map_info { /* description of an address space mapping */
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
index afc5f459e7..89c5ce47fa 100644
--- a/usr/src/lib/libproc/common/Pcore.c
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -2750,6 +2750,7 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr)
fp->file_ref = 1;
fp->file_fd = -1;
+ fp->file_dbgfile = -1;
fp->file_lo = malloc(sizeof (rd_loadobj_t));
fp->file_lname = strdup(execname);
diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c
index 5c12b6a716..db00268f9b 100644
--- a/usr/src/lib/libproc/common/Pidle.c
+++ b/usr/src/lib/libproc/common/Pidle.c
@@ -227,6 +227,7 @@ Pgrab_file(const char *fname, int *perr)
}
fp->file_fd = fd;
+ fp->file_dbgfile = -1;
fp->file_lo->rl_lmident = LM_ID_BASE;
if ((fp->file_lname = strdup(fp->file_pname)) == NULL) {
*perr = G_STRANGE;
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
index 62354f9a7b..aed64d7799 100644
--- a/usr/src/lib/libproc/common/Psymtab.c
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
@@ -43,6 +43,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
+#include <sys/crc32.h>
#include "libproc.h"
#include "Pcontrol.h"
@@ -61,6 +62,7 @@ static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uint_t *,
static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uint_t *,
uintptr_t);
#endif
+static uint32_t psym_crc32[] = { CRC32_TABLE };
#define DATA_TYPES \
((1 << STT_OBJECT) | (1 << STT_FUNC) | \
@@ -69,6 +71,22 @@ static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uint_t *,
#define MA_RWX (MA_READ | MA_WRITE | MA_EXEC)
+/*
+ * Minimum and maximum length of a build-id that we'll accept. Generally it's a
+ * 20 byte SHA1 and it's expected that the first byte (which is two ascii
+ * characters) indicates a directory and the remaining bytes become the file
+ * name. Therefore, our minimum length is at least 2 bytes (one for the
+ * directory and one for the name) and the max is a bit over the minimum -- 64,
+ * just in case folks do something odd. The string length is three times the max
+ * length. This accounts for the fact that each byte is two characters, a null
+ * terminator, and the directory '/' character.
+ */
+#define MINBUILDID 2
+#define MAXBUILDID 64
+#define BUILDID_STRLEN (3*MAXBUILDID)
+#define BUILDID_NAME ".note.gnu.build-id"
+#define DBGLINK_NAME ".gnu_debuglink"
+
typedef enum {
PRO_NATURAL,
PRO_BYADDR,
@@ -184,6 +202,7 @@ file_info_new(struct ps_prochandle *P, map_info_t *mptr)
mptr->map_file = fptr;
fptr->file_ref = 1;
fptr->file_fd = -1;
+ fptr->file_dbgfile = -1;
P->num_files++;
/*
@@ -274,6 +293,10 @@ file_info_free(struct ps_prochandle *P, file_info_t *fptr)
free(fptr->file_elfmem);
if (fptr->file_fd >= 0)
(void) close(fptr->file_fd);
+ if (fptr->file_dbgelf)
+ (void) elf_end(fptr->file_dbgelf);
+ if (fptr->file_dbgfile >= 0)
+ (void) close(fptr->file_dbgfile);
if (fptr->file_ctfp) {
ctf_close(fptr->file_ctfp);
free(fptr->file_ctf_buf);
@@ -721,6 +744,58 @@ Pname_to_loadobj(struct ps_prochandle *P, const char *name)
return (Plmid_to_loadobj(P, PR_LMID_EVERY, name));
}
+/*
+ * We've been given a file_info_t which doesn't have any CTF. However, it may
+ * have information that's in a format that we could convert if on the fly.
+ * We'll first try to convert the alternate debug file, if present, and then
+ * move onto the default file. The reason we prefer the alternate debug file is
+ * that if both exist, then it likely has any usable debugging information.
+ */
+static ctf_file_t *
+Pconvert_file_ctf(file_info_t *fptr)
+{
+ int err;
+ ctf_file_t *fp;
+ char errmsg[1024];
+
+ /*
+ * Provide an opt in.
+ */
+ if (getenv("LIBPROC_CTFCONVERT") == NULL)
+ return (NULL);
+
+ /*
+ * If we've already attempted to call this, then that's it. No reason to
+ * pretend we'll be more successful again another time.
+ */
+ if (fptr->file_cvt == B_TRUE)
+ return (NULL);
+ fptr->file_cvt = B_TRUE;
+
+ fp = NULL;
+ if (fptr->file_dbgelf != NULL) {
+ fp = ctf_elfconvert(fptr->file_fd, fptr->file_dbgelf, NULL, 1,
+ 0, &err, errmsg, sizeof (errmsg));
+ if (fp == NULL) {
+ dprintf("failed to convert %s: %s\n", fptr->file_pname,
+ err == ECTF_CONVBKERR ? errmsg : ctf_errmsg(err));
+ }
+ }
+ if (fp == NULL) {
+ fp = ctf_elfconvert(fptr->file_fd, fptr->file_elf, NULL, 1,
+ 0, &err, errmsg, sizeof (errmsg));
+ if (fp == NULL) {
+ dprintf("failed to convert %s: %s\n", fptr->file_pname,
+ err == ECTF_CONVBKERR ? errmsg : ctf_errmsg(err));
+ }
+ }
+ if (fp != NULL) {
+ fptr->file_ctfp = fp;
+ }
+
+ return (NULL);
+}
+
ctf_file_t *
Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr)
{
@@ -733,8 +808,9 @@ Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr)
Pbuild_file_symtab(P, fptr);
- if (fptr->file_ctf_size == 0)
- return (NULL);
+ if (fptr->file_ctf_size == 0) {
+ return (Pconvert_file_ctf(fptr));
+ }
symp = fptr->file_ctf_dyn ? &fptr->file_dynsym : &fptr->file_symtab;
if (symp->sym_data_pri == NULL)
@@ -819,14 +895,28 @@ ctf_file_t *
Plmid_to_ctf(struct ps_prochandle *P, Lmid_t lmid, const char *name)
{
map_info_t *mptr;
- file_info_t *fptr;
+ file_info_t *fptr = NULL;
if (name == PR_OBJ_EVERY)
return (NULL);
- if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
- (fptr = mptr->map_file) == NULL)
- return (NULL);
+ /*
+ * While most idle files are all ELF objects, not all of them have
+ * mapping information available. There's nothing which would make
+ * sense to fake up for ET_REL. Instead, if we're being asked for their
+ * executable object and we know that the information is valid and they
+ * only have a single file, we jump straight to that file pointer.
+ */
+ if (P->state == PS_IDLE && name == PR_OBJ_EXEC && P->info_valid == 1 &&
+ P->num_files == 1 && P->mappings == NULL) {
+ fptr = list_next(&P->file_head);
+ }
+
+ if (fptr == NULL) {
+ if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
+ (fptr = mptr->map_file) == NULL)
+ return (NULL);
+ }
return (Pbuild_file_ctf(P, fptr));
}
@@ -1544,7 +1634,7 @@ optimize_symtab(sym_tbl_t *symtab)
static Elf *
build_fake_elf(struct ps_prochandle *P, file_info_t *fptr, GElf_Ehdr *ehdr,
- size_t *nshdrs, Elf_Data **shdata)
+ size_t *nshdrs, Elf_Data **shdata)
{
size_t shstrndx;
Elf_Scn *scn;
@@ -1567,6 +1657,225 @@ build_fake_elf(struct ps_prochandle *P, file_info_t *fptr, GElf_Ehdr *ehdr,
}
/*
+ * Try and find the file described by path in the file system and validate that
+ * it matches our CRC before we try and process it for symbol information. If we
+ * instead have an ELF data section, then that means we're checking a build-id
+ * section instead. In that case we just need to find and bcmp the corresponding
+ * section.
+ *
+ * Before we validate if it's a valid CRC or data section, we check to ensure
+ * that it's a normal file and not anything else.
+ */
+static boolean_t
+build_alt_debug(file_info_t *fptr, const char *path, uint32_t crc,
+ Elf_Data *data)
+{
+ int fd;
+ struct stat st;
+ Elf *elf;
+ Elf_Scn *scn;
+ GElf_Shdr symshdr, strshdr;
+ Elf_Data *symdata, *strdata;
+ boolean_t valid;
+ uint32_t c = -1U;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ return (B_FALSE);
+
+ if (fstat(fd, &st) != 0) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+
+ if (S_ISREG(st.st_mode) == 0) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+
+ /*
+ * Only check the CRC if we've come here through a GNU debug link
+ * section as opposed to the build id. This is indicated by having the
+ * value of data be NULL.
+ */
+ if (data == NULL) {
+ for (;;) {
+ char buf[4096];
+ ssize_t ret = read(fd, buf, sizeof (buf));
+ if (ret == -1) {
+ if (ret == EINTR)
+ continue;
+ (void) close(fd);
+ return (B_FALSE);
+ }
+ if (ret == 0) {
+ c = ~c;
+ if (c != crc) {
+ dprintf("crc mismatch, found: 0x%x "
+ "expected 0x%x\n", c, crc);
+ (void) close(fd);
+ return (B_FALSE);
+ }
+ break;
+ }
+ CRC32(c, buf, ret, c, psym_crc32);
+ }
+ }
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == NULL) {
+ (void) close(fd);
+ return (B_FALSE);
+ }
+
+ if (elf_kind(elf) != ELF_K_ELF) {
+ goto fail;
+ }
+
+ /*
+ * If we have a data section, that indicates we have a build-id which
+ * means we need to find the corresponding build-id section and compare
+ * it.
+ */
+ scn = NULL;
+ valid = B_FALSE;
+ for (scn = elf_nextscn(elf, scn); data != NULL && scn != NULL;
+ scn = elf_nextscn(elf, scn)) {
+ GElf_Shdr hdr;
+ Elf_Data *ntdata;
+
+ if (gelf_getshdr(scn, &hdr) == NULL)
+ goto fail;
+
+ if (hdr.sh_type != SHT_NOTE)
+ continue;
+
+ if ((ntdata = elf_getdata(scn, NULL)) == NULL)
+ goto fail;
+
+ /*
+ * First verify the data section sizes are equal, then the
+ * section name. If that's all true, then we can just do a bcmp.
+ */
+ if (data->d_size != ntdata->d_size)
+ continue;
+
+ dprintf("found corresponding section in alternate file\n");
+ if (bcmp(ntdata->d_buf, data->d_buf, data->d_size) != 0)
+ goto fail;
+
+ valid = B_TRUE;
+ break;
+ }
+ if (data != NULL && valid == B_FALSE) {
+ dprintf("failed to find a matching %s section in %s\n",
+ BUILDID_NAME, path);
+ goto fail;
+ }
+
+
+ /*
+ * Do two passes, first see if we have a symbol header, then see if we
+ * can find the corresponding linked string table.
+ */
+ scn = NULL;
+ for (scn = elf_nextscn(elf, scn); scn != NULL;
+ scn = elf_nextscn(elf, scn)) {
+
+ if (gelf_getshdr(scn, &symshdr) == NULL)
+ goto fail;
+
+ if (symshdr.sh_type != SHT_SYMTAB)
+ continue;
+
+ if ((symdata = elf_getdata(scn, NULL)) == NULL)
+ goto fail;
+
+ break;
+ }
+ if (scn == NULL)
+ goto fail;
+
+ if ((scn = elf_getscn(elf, symshdr.sh_link)) == NULL)
+ goto fail;
+
+ if (gelf_getshdr(scn, &strshdr) == NULL)
+ goto fail;
+
+ if ((strdata = elf_getdata(scn, NULL)) == NULL)
+ goto fail;
+
+ fptr->file_symtab.sym_data_pri = symdata;
+ fptr->file_symtab.sym_symn += symshdr.sh_size / symshdr.sh_entsize;
+ fptr->file_symtab.sym_strs = strdata->d_buf;
+ fptr->file_symtab.sym_strsz = strdata->d_size;
+ fptr->file_symtab.sym_hdr_pri = symshdr;
+ fptr->file_symtab.sym_strhdr = strshdr;
+
+ dprintf("successfully loaded additional debug symbols for %s from %s\n",
+ fptr->file_rname, path);
+
+ fptr->file_dbgfile = fd;
+ fptr->file_dbgelf = elf;
+ return (B_TRUE);
+fail:
+ (void) elf_end(elf);
+ (void) close(fd);
+ return (B_FALSE);
+}
+
+/*
+ * We're here because the object in question has no symbol information, that's a
+ * bit unfortunate. However, we've found that there's a .gnu_debuglink sitting
+ * around. By convention that means that given the current location of the
+ * object on disk, and the debug name that we found in the binary we need to
+ * search the following locations for a matching file.
+ *
+ * <dirname>/.debug/<debug-name>
+ * /usr/lib/debug/<dirname>/<debug-name>
+ *
+ * In the future, we should consider supporting looking in the prefix's
+ * lib/debug directory for a matching object or supporting an arbitrary user
+ * defined set of places to look.
+ */
+static void
+find_alt_debuglink(file_info_t *fptr, const char *name, uint32_t crc)
+{
+ boolean_t r;
+ char *dup = NULL, *path = NULL, *dname;
+
+ dprintf("find_alt_debug: looking for %s, crc 0x%x\n", name, crc);
+ if (fptr->file_rname == NULL) {
+ dprintf("find_alt_debug: encountered null file_rname\n");
+ return;
+ }
+
+ dup = strdup(fptr->file_rname);
+ if (dup == NULL)
+ return;
+
+ dname = dirname(dup);
+ if (asprintf(&path, "%s/.debug/%s", dname, name) != -1) {
+ dprintf("attempting to load alternate debug information "
+ "from %s\n", path);
+ r = build_alt_debug(fptr, path, crc, NULL);
+ free(path);
+ if (r == B_TRUE)
+ goto out;
+ }
+
+ if (asprintf(&path, "/usr/lib/debug/%s/%s", dname, name) != -1) {
+ dprintf("attempting to load alternate debug information "
+ "from %s\n", path);
+ r = build_alt_debug(fptr, path, crc, NULL);
+ free(path);
+ if (r == B_TRUE)
+ goto out;
+ }
+out:
+ free(dup);
+}
+
+/*
* Build the symbol table for the given mapped file.
*/
void
@@ -1587,7 +1896,8 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
GElf_Shdr c_shdr;
Elf_Data *c_data;
const char *c_name;
- } *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL;
+ } *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL,
+ *dbglink = NULL, *buildid = NULL;
if (fptr->file_init)
return; /* We've already processed this file */
@@ -1813,7 +2123,151 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
continue;
}
ctf = cp;
+ } else if (strcmp(cp->c_name, BUILDID_NAME) == 0) {
+ dprintf("Found a %s section for %s\n", BUILDID_NAME,
+ fptr->file_rname);
+ /* The ElfXX_Nhdr is 32/64-bit neutral */
+ if (cp->c_shdr.sh_type == SHT_NOTE &&
+ cp->c_data->d_buf != NULL &&
+ cp->c_data->d_size >= sizeof (Elf32_Nhdr)) {
+ Elf32_Nhdr *hdr = cp->c_data->d_buf;
+ if (hdr->n_type != 3)
+ continue;
+ if (hdr->n_namesz != 4)
+ continue;
+ if (hdr->n_descsz < MINBUILDID)
+ continue;
+ /* Set a reasonable upper bound */
+ if (hdr->n_descsz > MAXBUILDID) {
+ dprintf("Skipped %s as too large "
+ "(%ld)\n", BUILDID_NAME,
+ (unsigned long)hdr->n_descsz);
+ continue;
+ }
+
+ if (cp->c_data->d_size < sizeof (hdr) +
+ hdr->n_namesz + hdr->n_descsz)
+ continue;
+ buildid = cp;
+ }
+ } else if (strcmp(cp->c_name, DBGLINK_NAME) == 0) {
+ dprintf("found %s section for %s\n", DBGLINK_NAME,
+ fptr->file_rname);
+ /*
+ * Let's make sure of a few things before we do this.
+ */
+ if (cp->c_shdr.sh_type == SHT_PROGBITS &&
+ cp->c_data->d_buf != NULL &&
+ cp->c_data->d_size) {
+ dbglink = cp;
+ }
+ }
+ }
+
+ /*
+ * If we haven't found any symbol table information and we have found
+ * either a .note.gnu.build-id or a .gnu_debuglink, it's time to try and
+ * figure out where we might find this. Originally, GNU used the
+ * .gnu_debuglink solely, but then they added a .note.gnu.build-id. The
+ * build-id is some size, usually 16 or 20 bytes, often a SHA1 sum of
+ * the old, but not present file. All that you have to do to compare
+ * things is see if the sections are less, in theory saving you from
+ * doing lots of expensive I/O.
+ *
+ * For the .note.gnu.build-id, we're going to check a few things before
+ * using it, first that the name is 4 bytes, and is GNU and that the
+ * type is 3, which they say is the build-id identifier.
+ *
+ * To verify that the elf data for the .gnu_debuglink seems somewhat
+ * sane, eg. the elf data should be a string, so we want to verify we
+ * have a null-terminator.
+ */
+ if (fptr->file_symtab.sym_data_pri == NULL && buildid != NULL) {
+ int i, bo;
+ uint8_t *dp;
+ char buf[BUILDID_STRLEN], *path;
+ Elf32_Nhdr *hdr = buildid->c_data->d_buf;
+
+ /*
+ * This was checked for validity when assigning the buildid
+ * variable.
+ */
+ bzero(buf, sizeof (buf));
+ dp = (uint8_t *)((uintptr_t)hdr + sizeof (*hdr) +
+ hdr->n_namesz);
+ for (i = 0, bo = 0; i < hdr->n_descsz; i++, bo += 2, dp++) {
+ assert(sizeof (buf) - bo > 0);
+
+ /*
+ * Recall that the build-id is structured as a series of
+ * bytes. However, the first two characters are supposed
+ * to represent a directory. Hence, once we reach offset
+ * two, we insert a '/' character.
+ */
+ if (bo == 2) {
+ buf[bo] = '/';
+ bo++;
+ }
+ (void) snprintf(buf + bo, sizeof (buf) - bo, "%2x",
+ *dp);
}
+
+ if (asprintf(&path, "/usr/lib/debug/.build-id/%s.debug",
+ buf) != -1) {
+ boolean_t r;
+ dprintf("attempting to find build id alternate debug "
+ "file at %s\n", path);
+ r = build_alt_debug(fptr, path, 0, buildid->c_data);
+ dprintf("attempt %s\n", r == B_TRUE ?
+ "succeeded" : "failed");
+ free(path);
+ } else {
+ dprintf("failed to construct build id path: %s\n",
+ strerror(errno));
+ }
+ }
+
+ if (fptr->file_symtab.sym_data_pri == NULL && dbglink != NULL) {
+ char *c = dbglink->c_data->d_buf;
+ size_t i;
+ boolean_t found = B_FALSE;
+ Elf_Data *ed = dbglink->c_data;
+ uint32_t crc;
+
+ for (i = 0; i < ed->d_size; i++) {
+ if (c[i] == '\0') {
+ uintptr_t off;
+ dprintf("got .gnu_debuglink terminator at "
+ "offset %lu\n", (unsigned long)i);
+ /*
+ * After the null terminator, there should be
+ * padding, followed by a 4 byte CRC of the
+ * file. If we don't see this, we're going to
+ * assume this is bogus.
+ */
+ if ((i % sizeof (uint32_t)) == 0) {
+ i += 4;
+ } else {
+ i += sizeof (uint32_t) -
+ (i % sizeof (uint32_t));
+ }
+ if (i + sizeof (uint32_t) ==
+ dbglink->c_data->d_size) {
+ found = B_TRUE;
+ off = (uintptr_t)ed->d_buf + i;
+ crc = *(uint32_t *)off;
+ } else {
+ dprintf(".gnu_debuglink size mismatch, "
+ "expected: %lu, found: %lu\n",
+ (unsigned long)i,
+ (unsigned long)ed->d_size);
+ }
+ break;
+ }
+ }
+
+ if (found == B_TRUE)
+ find_alt_debuglink(fptr, dbglink->c_data->d_buf, crc);
}
/*
@@ -1943,7 +2397,13 @@ bad:
fptr->file_elfmem = NULL;
}
(void) close(fptr->file_fd);
+ if (fptr->file_dbgelf != NULL)
+ (void) elf_end(fptr->file_dbgelf);
+ fptr->file_dbgelf = NULL;
+ if (fptr->file_dbgfile >= 0)
+ (void) close(fptr->file_dbgfile);
fptr->file_fd = -1;
+ fptr->file_dbgfile = -1;
}
/*
@@ -2579,7 +3039,7 @@ Pxlookup_by_name(
*/
int
Plookup_by_name(struct ps_prochandle *P, const char *object,
- const char *symbol, GElf_Sym *symp)
+ const char *symbol, GElf_Sym *symp)
{
return (Pxlookup_by_name(P, PR_LMID_EVERY, object, symbol, symp, NULL));
}
@@ -2677,7 +3137,7 @@ Pobject_iter_resolved(struct ps_prochandle *P, proc_map_f *func, void *cd)
static char *
i_Pobjname(struct ps_prochandle *P, boolean_t lmresolve, uintptr_t addr,
- char *buffer, size_t bufsize)
+ char *buffer, size_t bufsize)
{
map_info_t *mptr;
file_info_t *fptr;
@@ -2710,7 +3170,7 @@ i_Pobjname(struct ps_prochandle *P, boolean_t lmresolve, uintptr_t addr,
*/
char *
Pobjname(struct ps_prochandle *P, uintptr_t addr,
- char *buffer, size_t bufsize)
+ char *buffer, size_t bufsize)
{
return (i_Pobjname(P, B_FALSE, addr, buffer, bufsize));
}
@@ -2725,7 +3185,7 @@ Pobjname(struct ps_prochandle *P, uintptr_t addr,
*/
char *
Pobjname_resolved(struct ps_prochandle *P, uintptr_t addr,
- char *buffer, size_t bufsize)
+ char *buffer, size_t bufsize)
{
return (i_Pobjname(P, B_TRUE, addr, buffer, bufsize));
}
diff --git a/usr/src/lib/librename/Makefile b/usr/src/lib/librename/Makefile
new file mode 100644
index 0000000000..222523d9a1
--- /dev/null
+++ b/usr/src/lib/librename/Makefile
@@ -0,0 +1,44 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+HDRS = librename.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS) $(VARPD_MAPFILES) install_h
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/librename/Makefile.com b/usr/src/lib/librename/Makefile.com
new file mode 100644
index 0000000000..f0a22f25ac
--- /dev/null
+++ b/usr/src/lib/librename/Makefile.com
@@ -0,0 +1,34 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+LIBRARY = librename.a
+VERS = .1
+OBJECTS = librename.o \
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc
+CPPFLAGS += -I../common
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/librename/amd64/Makefile b/usr/src/lib/librename/amd64/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/librename/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/librename/common/librename.c b/usr/src/lib/librename/common/librename.c
new file mode 100644
index 0000000000..1e198a50a3
--- /dev/null
+++ b/usr/src/lib/librename/common/librename.c
@@ -0,0 +1,229 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * Implementation of librename(3RENAME) interfaces.
+ */
+
+#include <librename.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <synch.h>
+
+typedef enum librename_atomic_state {
+ LIBRENAME_ATOMIC_INITIAL = 0x0,
+ LIBRENAME_ATOMIC_FSYNC,
+ LIBRENAME_ATOMIC_RENAME,
+ LIBRENAME_ATOMIC_POSTSYNC,
+ LIBRENAME_ATOMIC_COMPLETED
+} librename_atomic_state_t;
+
+struct librename_atomic {
+ char *lra_fname; /* RO */
+ char *lra_altname; /* RO */
+ int lra_dirfd; /* RO */
+ int lra_tmpfd; /* RO */
+ mutex_t lra_lock;
+ librename_atomic_state_t lra_state; /* lra_lock */
+};
+
+int
+librename_atomic_fdinit(int fd, const char *file, const char *prefix,
+ int mode, int flags, librename_atomic_t **outp)
+{
+ int ret;
+ int oflags;
+ librename_atomic_t *lrap;
+ struct stat st;
+
+ if (fd < 0 || file == NULL || outp == NULL)
+ return (EINVAL);
+
+ if (flags & ~(LIBRENAME_ATOMIC_NOUNLINK | LIBRENAME_ATOMIC_CLOEXEC))
+ return (EINVAL);
+
+ if (strchr(file, '/') != NULL)
+ return (EINVAL);
+
+ if (prefix != NULL && strchr(prefix, '/') != NULL)
+ return (EINVAL);
+
+ *outp = NULL;
+ lrap = malloc(sizeof (librename_atomic_t));
+ if (lrap == NULL)
+ return (errno);
+
+ if (fstat(fd, &st) != 0) {
+ ret = errno;
+ free(lrap);
+ return (ret);
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ free(lrap);
+ return (ENOTDIR);
+ }
+
+ if ((lrap->lra_dirfd = dup(fd)) == -1) {
+ ret = errno;
+ free(lrap);
+ return (ret);
+ }
+
+
+ lrap->lra_fname = strdup(file);
+ if (lrap->lra_fname == NULL) {
+ ret = errno;
+ if (close(lrap->lra_dirfd) != 0)
+ abort();
+ free(lrap);
+ return (ret);
+ }
+
+ if (prefix == NULL) {
+ ret = asprintf(&lrap->lra_altname, ".%d.%s", (int)getpid(),
+ file);
+ } else {
+ ret = asprintf(&lrap->lra_altname, "%s%s", prefix, file);
+ }
+ if (ret == -1) {
+ ret = errno;
+ free(lrap->lra_fname);
+ if (close(lrap->lra_dirfd) != 0)
+ abort();
+ free(lrap);
+ return (errno);
+ }
+
+ oflags = O_CREAT | O_TRUNC | O_RDWR | O_NOFOLLOW;
+ if (flags & LIBRENAME_ATOMIC_NOUNLINK)
+ oflags |= O_EXCL;
+
+ if (flags & LIBRENAME_ATOMIC_CLOEXEC)
+ oflags |= O_CLOEXEC;
+
+ lrap->lra_tmpfd = openat(lrap->lra_dirfd, lrap->lra_altname,
+ oflags, mode);
+ if (lrap->lra_tmpfd < 0) {
+ ret = errno;
+ free(lrap->lra_altname);
+ free(lrap->lra_fname);
+ if (close(lrap->lra_dirfd) != 0)
+ abort();
+ free(lrap);
+ return (ret);
+ }
+
+ if (mutex_init(&lrap->lra_lock, USYNC_THREAD, NULL) != 0)
+ abort();
+
+ lrap->lra_state = LIBRENAME_ATOMIC_INITIAL;
+ *outp = lrap;
+ return (0);
+}
+
+int
+librename_atomic_init(const char *dir, const char *file, const char *prefix,
+ int mode, int flags, librename_atomic_t **outp)
+{
+ int fd, ret;
+
+ if ((fd = open(dir, O_RDONLY)) < 0)
+ return (errno);
+
+ ret = librename_atomic_fdinit(fd, file, prefix, mode, flags, outp);
+ if (close(fd) != 0)
+ abort();
+
+ return (ret);
+}
+
+int
+librename_atomic_fd(librename_atomic_t *lrap)
+{
+ return (lrap->lra_tmpfd);
+}
+
+/*
+ * To atomically commit a file, we need to go through and do the following:
+ *
+ * o fsync the source
+ * o run rename
+ * o fsync the source again and the directory.
+ */
+int
+librename_atomic_commit(librename_atomic_t *lrap)
+{
+ int ret = 0;
+
+ if (mutex_lock(&lrap->lra_lock) != 0)
+ abort();
+ if (lrap->lra_state == LIBRENAME_ATOMIC_COMPLETED) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ if (fsync(lrap->lra_tmpfd) != 0) {
+ ret = errno;
+ goto out;
+ }
+ lrap->lra_state = LIBRENAME_ATOMIC_FSYNC;
+
+ if (renameat(lrap->lra_dirfd, lrap->lra_altname, lrap->lra_dirfd,
+ lrap->lra_fname) != 0) {
+ ret = errno;
+ goto out;
+ }
+ lrap->lra_state = LIBRENAME_ATOMIC_RENAME;
+
+ if (fsync(lrap->lra_tmpfd) != 0) {
+ ret = errno;
+ goto out;
+ }
+ lrap->lra_state = LIBRENAME_ATOMIC_POSTSYNC;
+
+ if (fsync(lrap->lra_dirfd) != 0) {
+ ret = errno;
+ goto out;
+ }
+ lrap->lra_state = LIBRENAME_ATOMIC_COMPLETED;
+
+out:
+ if (mutex_unlock(&lrap->lra_lock) != 0)
+ abort();
+ return (ret);
+}
+
+void
+librename_atomic_fini(librename_atomic_t *lrap)
+{
+
+ free(lrap->lra_altname);
+ free(lrap->lra_fname);
+ if (close(lrap->lra_tmpfd) != 0)
+ abort();
+ if (close(lrap->lra_dirfd) != 0)
+ abort();
+ if (mutex_destroy(&lrap->lra_lock) != 0)
+ abort();
+ free(lrap);
+}
diff --git a/usr/src/lib/librename/common/librename.h b/usr/src/lib/librename/common/librename.h
new file mode 100644
index 0000000000..cb344f534c
--- /dev/null
+++ b/usr/src/lib/librename/common/librename.h
@@ -0,0 +1,43 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LIBRENAME_H
+#define _LIBRENAME_H
+
+/*
+ * librename(3RENAME) public interfaces
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct librename_atomic librename_atomic_t;
+
+#define LIBRENAME_ATOMIC_NOUNLINK 0x01
+#define LIBRENAME_ATOMIC_CLOEXEC 0x02
+extern int librename_atomic_init(const char *, const char *, const char *,
+ int, int, librename_atomic_t **);
+extern int librename_atomic_fdinit(int, const char *, const char *, int, int,
+ librename_atomic_t **);
+extern int librename_atomic_fd(librename_atomic_t *);
+extern int librename_atomic_commit(librename_atomic_t *);
+extern void librename_atomic_fini(librename_atomic_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBRENAME_H */
diff --git a/usr/src/lib/librename/common/llib-lrename b/usr/src/lib/librename/common/llib-lrename
new file mode 100644
index 0000000000..6f1dd81a7b
--- /dev/null
+++ b/usr/src/lib/librename/common/llib-lrename
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <librename.h>
diff --git a/usr/src/lib/librename/common/mapfile-vers b/usr/src/lib/librename/common/mapfile-vers
new file mode 100644
index 0000000000..af98188b42
--- /dev/null
+++ b/usr/src/lib/librename/common/mapfile-vers
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate {
+ global:
+ librename_atomic_commit;
+ librename_atomic_fd;
+ librename_atomic_fdinit;
+ librename_atomic_fini;
+ librename_atomic_init;
+ local:
+ *;
+};
diff --git a/usr/src/lib/librename/i386/Makefile b/usr/src/lib/librename/i386/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/librename/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/librename/sparc/Makefile b/usr/src/lib/librename/sparc/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/librename/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/librename/sparcv9/Makefile b/usr/src/lib/librename/sparcv9/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/librename/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libresolv2_joy/Makefile b/usr/src/lib/libresolv2_joy/Makefile
new file mode 100644
index 0000000000..052dfdd092
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/Makefile
@@ -0,0 +1,76 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+include ../../Makefile.master
+include ../Makefile.lib
+
+$(ROOTSVCMETHOD) := FILEMODE = 0555
+
+SUBDIRS= include $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+LIBRARY= libresolv_joy.a
+TEXT_DOMAIN= SUNW_OST_OSLIB
+XGETFLAGS= -a
+POFILE= $(LIBRARY:.a=.po)
+POFILES= generic.po
+
+SED= sed
+GREP= grep
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS)
+
+check: $(CHECKHDRS) $(CHKMANIFEST)
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) *.[ch]* */*.[ch]*
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET); echo
+
+FRC:
+
diff --git a/usr/src/lib/libresolv2_joy/Makefile.com b/usr/src/lib/libresolv2_joy/Makefile.com
new file mode 100644
index 0000000000..bbabcbcede
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/Makefile.com
@@ -0,0 +1,162 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+LIBRARY= libresolv_joy.a
+VERS= .2
+
+BSDOBJS= daemon.o putenv.o strcasecmp.o strsep.o \
+ ftruncate.o readv.o strdup.o strtoul.o \
+ gettimeofday.o setenv.o strerror.o utimes.o \
+ mktemp.o setitimer.o strpbrk.o writev.o
+
+DSTOBJS= dst_api.o support.o hmac_link.o
+
+# inet_addr, inet_pton, inet_ntop, and inet_ntoa removed due to overlap with
+# libnsl
+INETOBJS= inet_net_pton.o inet_neta.o inet_lnaof.o \
+ inet_netof.o nsap_addr.o inet_makeaddr.o \
+ inet_network.o inet_net_ntop.o inet_cidr_ntop.o \
+ inet_cidr_pton.o inet_data.o
+
+# build only the IRS objects that the ISC libbind's make would
+IRSTHROBJS= gethostent_r.o getnetent_r.o getnetgrent_r.o \
+ getprotoent_r.o getservent_r.o
+IRSOBJS= ${IRSTHROBJS} \
+ dns.o dns_ho.o dns_nw.o dns_pr.o \
+ dns_sv.o gai_strerror.o gen.o gen_ho.o \
+ gen_ng.o gen_nw.o gen_pr.o gen_sv.o \
+ getaddrinfo.o gethostent.o getnameinfo.o getnetent.o \
+ getnetgrent.o getprotoent.o getservent.o hesiod.o \
+ irp.o irp_ho.o irp_ng.o irp_nw.o \
+ irp_pr.o irp_sv.o irpmarshall.o irs_data.o \
+ lcl.o lcl_ho.o lcl_ng.o lcl_nw.o \
+ lcl_pr.o lcl_sv.o nis.o nul_ng.o \
+ util.o
+
+ISCOBJS= assertions.o base64.o bitncmp.o ctl_clnt.o \
+ ctl_p.o ctl_srvr.o ev_connects.o ev_files.o \
+ ev_streams.o ev_timers.o ev_waits.o eventlib.o \
+ heap.o hex.o logging.o memcluster.o \
+ movefile.o tree.o
+
+NAMESEROBJS= ns_date.o ns_name.o ns_netint.o ns_parse.o \
+ ns_print.o ns_samedomain.o ns_sign.o ns_ttl.o \
+ ns_verify.o ns_rdata.o ns_newmsg.o
+
+RESOLVOBJS= herror.o mtctxres.o res_comp.o res_data.o \
+ res_debug.o res_findzonecut.o res_init.o \
+ res_mkquery.o res_mkupdate.o res_query.o res_send.o \
+ res_sendsigned.o res_update.o
+
+SUNWOBJS= sunw_mtctxres.o sunw_updrec.o sunw_wrappers.o
+
+OBJECTS= $(BSDOBJS) $(DSTOBJS) $(INETOBJS) $(IRSOBJS) $(ISCOBJS) \
+ $(NAMESEROBJS) $(RESOLVOBJS) $(SUNWOBJS)
+
+# include library definitions
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+# CC -v complains about things we aren't going to change in the ISC code
+CCVERBOSE=
+
+SRCDIR = ../common
+SRCS= $(BSDOBJS:%.o=../common/bsd/%.c) \
+ $(DSTOBJS:%.o=../common/dst/%.c) \
+ $(INETOBJS:%.o=../common/inet/%.c) \
+ $(IRSOBJS:%.o=../common/irs/%.c) \
+ $(ISCOBJS:%.o=../common/isc/%.c) \
+ $(NAMESEROBJS:%.o=../common/nameser/%.c) \
+ $(RESOLVOBJS:%.o=../common/resolv/%.c) \
+ $(SUNWOBJS:%.o=../common/sunw/%.c)
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+$(LINTLIB):= SRCS = ../common/llib-lresolv_joy
+
+# Local Libresolv definitions
+
+SOLCOMPAT = -Dsocket=_socket
+CRYPTFLAGS= -DHMAC_MD5 -DUSE_MD5
+
+LOCFLAGS += $(CRYPTFLAGS)
+LOCFLAGS += -D_SYS_STREAM_H -D_REENTRANT -DSVR4 -DSUNW_OPTIONS \
+ $(SOLCOMPAT) -I../include -I../../common/inc
+
+CPPFLAGS += $(LOCFLAGS)
+
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+
+DYNFLAGS += $(ZNODELETE)
+
+LDLIBS += -lsocket -lnsl -lc -lmd
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+# include library targets
+include ../../Makefile.targ
+
+pics/%.o: ../common/bsd/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/dst/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/inet/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/irs/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/isc/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/nameser/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/resolv/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../common/sunw/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+# install rule for lint library target
+$(ROOTLINTDIR)/%: ../common/%
+ $(INS.file)
diff --git a/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE b/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..719d77fea2
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE
@@ -0,0 +1,185 @@
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+
+/* Copyright (C) RSA Data Security, Inc. created 1986-1987, 1990,
+ 1992-1994, 1996. This is an
+ unpublished work protected as such under copyright law. This work
+ contains proprietary, confidential, and trade secret information of
+ RSA Data Security, Inc. Use, disclosure or reproduction without the
+ express written authorization of RSA Data Security, Inc. is
+ prohibited.
+ */
+
+ DNSSAFE LICENSE TERMS
+
+ This BIND software includes the DNSsafe software from RSA Data
+ Security, Inc., which is copyrighted software that can only be
+ distributed under the terms of this license agreement.
+
+ The DNSsafe software cannot be used or distributed separately from the
+ BIND software. You only have the right to use it or distribute it as
+ a bundled, integrated product.
+
+ The DNSsafe software can ONLY be used to provide authentication for
+ resource records in the Domain Name System, as specified in RFC 2065
+ and successors. You cannot modify the BIND software to use the
+ DNSsafe software for other purposes, or to make its cryptographic
+ functions available to end-users for other uses.
+
+ If you modify the DNSsafe software itself, you cannot modify its
+ documented API, and you must grant RSA Data Security the right to use,
+ modify, and distribute your modifications, including the right to use
+ any patents or other intellectual property that your modifications
+ depend upon.
+
+ You must not remove, alter, or destroy any of RSA's copyright notices
+ or license information. When distributing the software to the Federal
+ Government, it must be licensed to them as "commercial computer
+ software" protected under 48 CFR 12.212 of the FAR, or 48 CFR
+ 227.7202.1 of the DFARS.
+
+ You must not violate United States export control laws by distributing
+ the DNSsafe software or information about it, when such distribution
+ is prohibited by law.
+
+ THE DNSSAFE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY
+ WHATSOEVER. RSA HAS NO OBLIGATION TO SUPPORT, CORRECT, UPDATE OR
+ MAINTAIN THE RSA SOFTWARE. RSA DISCLAIMS ALL WARRANTIES, EXPRESS,
+ IMPLIED OR STATUTORY, AS TO ANY MATTER WHATSOEVER, INCLUDING ALL
+ IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS.
+
+ If you desire to use DNSsafe in ways that these terms do not permit,
+ please contact RSA Data Security, Inc., 100 Marine Parkway, Redwood
+ City, California 94065, USA, to discuss alternate licensing
+ arrangements.
+
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
diff --git a/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE.descrip b/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..67315d8f33
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+BIND SOFTWARE
diff --git a/usr/src/lib/libresolv2_joy/amd64/Makefile b/usr/src/lib/libresolv2_joy/amd64/Makefile
new file mode 100644
index 0000000000..2e8cdecf75
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/amd64/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/daemon.c b/usr/src/lib/libresolv2_joy/common/bsd/daemon.c
new file mode 100644
index 0000000000..54ff83b753
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/daemon.c
@@ -0,0 +1,81 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)daemon.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: daemon.c,v 1.2 2005/04/27 04:56:10 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#ifndef NEED_DAEMON
+int __bind_daemon__;
+#else
+
+int
+daemon(int nochdir, int noclose) {
+ int fd;
+
+ switch (fork()) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ _exit(0);
+ }
+
+ if (setsid() == -1)
+ return (-1);
+
+ if (!nochdir)
+ (void)chdir("/");
+
+ if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)dup2(fd, STDIN_FILENO);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close (fd);
+ }
+ return (0);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/ftruncate.c b/usr/src/lib/libresolv2_joy/common/bsd/ftruncate.c
new file mode 100644
index 0000000000..5ac4ebac9b
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/ftruncate.c
@@ -0,0 +1,64 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: ftruncate.c,v 1.3 2005/04/27 18:16:45 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * ftruncate - set file size, BSD Style
+ *
+ * shortens or enlarges the file as neeeded
+ * uses some undocumented locking call. It is known to work on SCO unix,
+ * other vendors should try.
+ * The #error directive prevents unsupported OSes
+ */
+
+#include "port_before.h"
+
+#if defined(M_UNIX)
+#define OWN_FTRUNCATE
+#include <stdio.h>
+#ifdef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE
+#endif
+#ifdef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+#include <fcntl.h>
+
+#include "port_after.h"
+
+int
+__ftruncate(int fd, long wantsize) {
+ long cursize;
+
+ /* determine current file size */
+ if ((cursize = lseek(fd, 0L, 2)) == -1)
+ return (-1);
+
+ /* maybe lengthen... */
+ if (cursize < wantsize) {
+ if (lseek(fd, wantsize - 1, 0) == -1 ||
+ write(fd, "", 1) == -1) {
+ return (-1);
+ }
+ return (0);
+ }
+
+ /* maybe shorten... */
+ if (wantsize < cursize) {
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = wantsize;
+ fl.l_type = F_WRLCK;
+ return (fcntl(fd, F_FREESP, &fl));
+ }
+ return (0);
+}
+#endif
+
+#ifndef OWN_FTRUNCATE
+int __bindcompat_ftruncate;
+#endif
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/gettimeofday.c b/usr/src/lib/libresolv2_joy/common/bsd/gettimeofday.c
new file mode 100644
index 0000000000..2926a3575e
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/gettimeofday.c
@@ -0,0 +1,62 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: gettimeofday.c,v 1.4 2005/04/27 04:56:11 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include "port_after.h"
+
+#if !defined(NEED_GETTIMEOFDAY)
+/*%
+ * gettimeofday() occasionally returns invalid tv_usec on some platforms.
+ */
+#define MILLION 1000000
+#undef gettimeofday
+
+int
+isc__gettimeofday(struct timeval *tp, struct timezone *tzp) {
+ int res;
+
+ res = gettimeofday(tp, tzp);
+ if (res < 0)
+ return (res);
+ if (tp == NULL)
+ return (res);
+ if (tp->tv_usec < 0) {
+ do {
+ tp->tv_usec += MILLION;
+ tp->tv_sec--;
+ } while (tp->tv_usec < 0);
+ goto log;
+ } else if (tp->tv_usec > MILLION) {
+ do {
+ tp->tv_usec -= MILLION;
+ tp->tv_sec++;
+ } while (tp->tv_usec > MILLION);
+ goto log;
+ }
+ return (res);
+ log:
+ syslog(LOG_ERR, "gettimeofday: tv_usec out of range\n");
+ return (res);
+}
+#else
+int
+gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp) {
+ time_t clock, time(time_t *);
+
+ if (time(&clock) == (time_t) -1)
+ return (-1);
+ if (tvp) {
+ tvp->tv_sec = clock;
+ tvp->tv_usec = 0;
+ }
+ if (tzp) {
+ tzp->tz_minuteswest = 0;
+ tzp->tz_dsttime = 0;
+ }
+ return (0);
+}
+#endif /*NEED_GETTIMEOFDAY*/
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/mktemp.c b/usr/src/lib/libresolv2_joy/common/bsd/mktemp.c
new file mode 100644
index 0000000000..001b24b58f
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/mktemp.c
@@ -0,0 +1,156 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: mktemp.c,v 1.2 2005/04/27 04:56:11 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "port_after.h"
+
+#if (!defined(NEED_MKTEMP)) && (!defined(NEED_MKSTEMP))
+int __mktemp_unneeded__;
+#else
+
+static int gettemp(char *path, int *doopen);
+
+#ifdef NEED_MKSTEMP
+mkstemp(char *path) {
+ int fd;
+
+ return (gettemp(path, &fd) ? fd : -1);
+}
+#endif
+
+#ifdef NEED_MKTEMP
+char *
+mktemp(char *path) {
+ return(gettemp(path, (int *)NULL) ? path : (char *)NULL);
+}
+#endif
+
+static int
+gettemp(char *path, int *doopen) {
+ char *start, *trv;
+ struct stat sbuf;
+ u_int pid;
+
+ pid = getpid();
+ for (trv = path; *trv; ++trv); /*%< extra X's get set to 0's */
+ while (*--trv == 'X') {
+ *trv = (pid % 10) + '0';
+ pid /= 10;
+ }
+
+ /*
+ * check the target directory; if you have six X's and it
+ * doesn't exist this runs for a *very* long time.
+ */
+ for (start = trv + 1;; --trv) {
+ if (trv <= path)
+ break;
+ if (*trv == '/') {
+ *trv = '\0';
+ if (stat(path, &sbuf))
+ return(0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return(0);
+ }
+ *trv = '/';
+ break;
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+ return(1);
+ if (errno != EEXIST)
+ return(0);
+ }
+ else if (stat(path, &sbuf))
+ return(errno == ENOENT ? 1 : 0);
+
+ /* tricky little algorithm for backward compatibility */
+ for (trv = start;;) {
+ if (!*trv)
+ return(0);
+ if (*trv == 'z')
+ *trv++ = 'a';
+ else {
+ if (isdigit(*trv))
+ *trv = 'a';
+ else
+ ++*trv;
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
+
+#endif /*NEED_MKTEMP*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/putenv.c b/usr/src/lib/libresolv2_joy/common/bsd/putenv.c
new file mode 100644
index 0000000000..2dcbc57e6c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/putenv.c
@@ -0,0 +1,27 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: putenv.c,v 1.2 2005/04/27 04:56:11 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "port_after.h"
+
+/*%
+ * To give a little credit to Sun, SGI,
+ * and many vendors in the SysV world.
+ */
+
+#if !defined(NEED_PUTENV)
+int __bindcompat_putenv;
+#else
+int
+putenv(char *str) {
+ char *tmp;
+
+ for (tmp = str; *tmp && (*tmp != '='); tmp++)
+ ;
+
+ return (setenv(str, tmp, 1));
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/readv.c b/usr/src/lib/libresolv2_joy/common/bsd/readv.c
new file mode 100644
index 0000000000..5fa691a92f
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/readv.c
@@ -0,0 +1,39 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: readv.c,v 1.2 2005/04/27 04:56:11 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_READV
+int __bindcompat_readv;
+#else
+
+int
+__readv(fd, vp, vpcount)
+ int fd;
+ const struct iovec *vp;
+ int vpcount;
+{
+ int count = 0;
+
+ while (vpcount-- > 0) {
+ int bytes = read(fd, vp->iov_base, vp->iov_len);
+
+ if (bytes < 0)
+ return (-1);
+ count += bytes;
+ if (bytes != vp->iov_len)
+ break;
+ vp++;
+ }
+ return (count);
+}
+#endif /* NEED_READV */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/setenv.c b/usr/src/lib/libresolv2_joy/common/bsd/setenv.c
new file mode 100644
index 0000000000..baf00f6ff2
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/setenv.c
@@ -0,0 +1,151 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: setenv.c,v 1.2 2005/04/27 04:56:11 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#if !defined(NEED_SETENV)
+int __bindcompat_setenv;
+#else
+
+extern char **environ;
+
+static char *findenv(const char *name, int *offset);
+
+/*%
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+setenv(const char *name, const char *value, int rewrite) {
+ extern char **environ;
+ static int alloced; /*%< if allocated space before */
+ char *c;
+ int l_value, offset;
+
+ if (*value == '=') /*%< no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = findenv(name, &offset))) { /*%< find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /*%< old larger; copy over */
+ while (*c++ = *value++);
+ return (0);
+ }
+ } else { /*%< create new slot */
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced) { /*%< just increase size */
+ environ = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!environ)
+ return (-1);
+ }
+ else { /*%< get new space */
+ alloced = 1; /*%< copy old entries into it */
+ p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ memcpy(p, environ, cnt * sizeof(char *));
+ environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /*%< no `=' in name */
+ if (!(environ[offset] = /*%< name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; *c++ = *value++;);
+ return (0);
+}
+
+/*%
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(const char *name) {
+ char **p;
+ int offset;
+
+ while (findenv(name, &offset)) /*%< if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
+
+/*%
+ * findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ *
+ * This routine *should* be a static; don't use it.
+ */
+static char *
+findenv(const char *name, int *offset) {
+ const char *np;
+ char **p, *c;
+ int len;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (c = *p) != NULL; ++p)
+ if (strncmp(c, name, len) == 0 && c[len] == '=') {
+ *offset = p - environ;
+ return (c + len + 1);
+ }
+ return (NULL);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/setitimer.c b/usr/src/lib/libresolv2_joy/common/bsd/setitimer.c
new file mode 100644
index 0000000000..67881d7ca8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/setitimer.c
@@ -0,0 +1,29 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: setitimer.c,v 1.2 2005/04/27 04:56:12 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/time.h>
+
+#include "port_after.h"
+
+/*%
+ * Setitimer emulation routine.
+ */
+#ifndef NEED_SETITIMER
+int __bindcompat_setitimer;
+#else
+
+int
+__setitimer(int which, const struct itimerval *value,
+ struct itimerval *ovalue)
+{
+ if (alarm(value->it_value.tv_sec) >= 0)
+ return (0);
+ else
+ return (-1);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strcasecmp.c b/usr/src/lib/libresolv2_joy/common/bsd/strcasecmp.c
new file mode 100644
index 0000000000..0c9f0dccf0
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strcasecmp.c
@@ -0,0 +1,124 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strcasecmp.c,v 1.2 2005/04/27 04:56:12 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRCASECMP
+int __strcasecmp_unneeded__;
+#else
+
+/*%
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison. The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
+ 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+ 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
+ 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
+ 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+ 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+ 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
+ 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
+ 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+ 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+ 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+ 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
+};
+
+int
+strcasecmp(const char *s1, const char *s2) {
+ const u_char *cm = charmap,
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ while (cm[*us1] == cm[*us2++])
+ if (*us1++ == '\0')
+ return (0);
+ return (cm[*us1] - cm[*--us2]);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n) {
+ if (n != 0) {
+ const u_char *cm = charmap,
+ *us1 = (const u_char *)s1,
+ *us2 = (const u_char *)s2;
+
+ do {
+ if (cm[*us1] != cm[*us2++])
+ return (cm[*us1] - cm[*--us2]);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return (0);
+}
+
+#endif /*NEED_STRCASECMP*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strdup.c b/usr/src/lib/libresolv2_joy/common/bsd/strdup.c
new file mode 100644
index 0000000000..a8d31e9587
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strdup.c
@@ -0,0 +1,20 @@
+#include "port_before.h"
+
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRDUP
+int __bind_strdup_unneeded;
+#else
+char *
+strdup(const char *src) {
+ char *dst = malloc(strlen(src) + 1);
+
+ if (dst)
+ strcpy(dst, src);
+ return (dst);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strerror.c b/usr/src/lib/libresolv2_joy/common/bsd/strerror.c
new file mode 100644
index 0000000000..5973e63d5b
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strerror.c
@@ -0,0 +1,94 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strerror.c,v 1.6 2008/02/18 03:49:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRERROR
+int __strerror_unneeded__;
+#else
+
+#ifdef USE_SYSERROR_LIST
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif
+
+const char *
+isc_strerror(int num) {
+#define UPREFIX "Unknown error: "
+ static char ebuf[40] = UPREFIX; /*%< 64-bit number + slop */
+ u_int errnum;
+ char *p, *t;
+#ifndef USE_SYSERROR_LIST
+ const char *ret;
+#endif
+ char tmp[40];
+
+ errnum = num; /*%< convert to unsigned */
+#ifdef USE_SYSERROR_LIST
+ if (errnum < (u_int)sys_nerr)
+ return (sys_errlist[errnum]);
+#else
+#undef strerror
+ ret = strerror(num); /*%< call strerror() in libc */
+ if (ret != NULL)
+ return(ret);
+#endif
+
+ /* Do this by hand, so we don't include stdio(3). */
+ t = tmp;
+ do {
+ *t++ = "0123456789"[errnum % 10];
+ } while (errnum /= 10);
+ for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+ *p++ = *--t;
+ if (t <= tmp)
+ break;
+ }
+ return (ebuf);
+}
+
+#endif /*NEED_STRERROR*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strpbrk.c b/usr/src/lib/libresolv2_joy/common/bsd/strpbrk.c
new file mode 100644
index 0000000000..4c12d88e1c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strpbrk.c
@@ -0,0 +1,70 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strpbrk.c,v 1.2 2005/04/27 04:56:12 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRPBRK
+int __strpbrk_unneeded__;
+#else
+
+/*%
+ * Find the first occurrence in s1 of a character in s2 (excluding NUL).
+ */
+char *
+strpbrk(const char *s1, const char *s2) {
+ const char *scanp;
+ int c, sc;
+
+ while ((c = *s1++) != 0) {
+ for (scanp = s2; (sc = *scanp++) != 0;)
+ if (sc == c)
+ return ((char *)(s1 - 1));
+ }
+ return (NULL);
+}
+
+#endif /*NEED_STRPBRK*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strsep.c b/usr/src/lib/libresolv2_joy/common/bsd/strsep.c
new file mode 100644
index 0000000000..c7969f0028
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strsep.c
@@ -0,0 +1,88 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strsep.c,v 1.2 2005/04/27 04:56:12 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+#include <sys/cdefs.h>
+#include <string.h>
+#include <stdio.h>
+#include "port_after.h"
+
+#ifndef NEED_STRSEP
+int __strsep_unneeded__;
+#else
+
+/*%
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim) {
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+#endif /*NEED_STRSEP*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/strtoul.c b/usr/src/lib/libresolv2_joy/common/bsd/strtoul.c
new file mode 100644
index 0000000000..b37ff72729
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/strtoul.c
@@ -0,0 +1,119 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strtoul.c,v 1.4 2008/02/18 03:49:08 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRTOUL
+int __strtoul_unneeded__;
+#else
+
+/*%
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+u_long
+strtoul(const char *nptr, char **endptr, int base) {
+ const char *s = nptr;
+ u_long acc, cutoff;
+ int neg, c, any, cutlim;
+
+ neg = 0;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *(const unsigned char *)s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (u_long)ULONG_MAX / (u_long)base;
+ cutlim = (u_long)ULONG_MAX % (u_long)base;
+ for (acc = 0, any = 0;; c = *(const unsigned char*)s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ DE_CONST((any ? s - 1 : nptr), *endptr);
+ return (acc);
+}
+
+#endif /*NEED_STRTOUL*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/utimes.c b/usr/src/lib/libresolv2_joy/common/bsd/utimes.c
new file mode 100644
index 0000000000..2f65cffe25
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/utimes.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utime.h>
+
+#include "port_after.h"
+
+#ifndef NEED_UTIMES
+int __bind_utimes_unneeded;
+#else
+
+int
+__utimes(char *filename, struct timeval *tvp) {
+ struct utimbuf utb;
+
+ utb.actime = (time_t)tvp[0].tv_sec;
+ utb.modtime = (time_t)tvp[1].tv_sec;
+ return (utime(filename, &utb));
+}
+
+#endif /* NEED_UTIMES */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/bsd/writev.c b/usr/src/lib/libresolv2_joy/common/bsd/writev.c
new file mode 100644
index 0000000000..65baa71cfc
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/bsd/writev.c
@@ -0,0 +1,89 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: writev.c,v 1.3 2005/04/27 04:56:13 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_WRITEV
+int __bindcompat_writev;
+#else
+
+#ifdef _CRAY
+#define OWN_WRITEV
+int
+__writev(int fd, struct iovec *iov, int iovlen)
+{
+ struct stat statbuf;
+
+ if (fstat(fd, &statbuf) < 0)
+ return (-1);
+
+ /*
+ * Allow for atomic writes to network.
+ */
+ if (statbuf.st_mode & S_IFSOCK) {
+ struct msghdr mesg;
+
+ memset(&mesg, 0, sizeof(mesg));
+ mesg.msg_name = 0;
+ mesg.msg_namelen = 0;
+ mesg.msg_iov = iov;
+ mesg.msg_iovlen = iovlen;
+ mesg.msg_accrights = 0;
+ mesg.msg_accrightslen = 0;
+ return (sendmsg(fd, &mesg, 0));
+ } else {
+ struct iovec *tv;
+ int i, rcode = 0, count = 0;
+
+ for (i = 0, tv = iov; i <= iovlen; tv++) {
+ rcode = write(fd, tv->iov_base, tv->iov_len);
+
+ if (rcode < 0)
+ break;
+
+ count += rcode;
+ }
+
+ if (count == 0)
+ return (rcode);
+ else
+ return (count);
+ }
+}
+
+#else /*_CRAY*/
+
+int
+__writev(fd, vp, vpcount)
+ int fd;
+ const struct iovec *vp;
+ int vpcount;
+{
+ int count = 0;
+
+ while (vpcount-- > 0) {
+ int written = write(fd, vp->iov_base, vp->iov_len);
+
+ if (written < 0)
+ return (-1);
+ count += written;
+ if (written != vp->iov_len)
+ break;
+ vp++;
+ }
+ return (count);
+}
+
+#endif /*_CRAY*/
+
+#endif /*NEED_WRITEV*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/dst/dst_api.c b/usr/src/lib/libresolv2_joy/common/dst/dst_api.c
new file mode 100644
index 0000000000..a3e48077ad
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/dst/dst_api.c
@@ -0,0 +1,1048 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/prod/libbind/dst/dst_api.c,v 1.17 2007/09/24 17:18:25 each Exp $";
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+/*
+ * This file contains the interface between the DST API and the crypto API.
+ * This is the only file that needs to be changed if the crypto system is
+ * changed. Exported functions are:
+ * void dst_init() Initialize the toolkit
+ * int dst_check_algorithm() Function to determines if alg is suppored.
+ * int dst_compare_keys() Function to compare two keys for equality.
+ * int dst_sign_data() Incremental signing routine.
+ * int dst_verify_data() Incremental verify routine.
+ * int dst_generate_key() Function to generate new KEY
+ * DST_KEY *dst_read_key() Function to retrieve private/public KEY.
+ * void dst_write_key() Function to write out a key.
+ * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST
+ * KEY structure.
+ * int dst_key_to_dnskey() Function to return a public key in DNS
+ * format binary
+ * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY
+ * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer
+ * void dst_free_key() Releases all memory referenced by key structure
+ */
+
+#include "port_before.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include "dst_internal.h"
+#include "port_after.h"
+
+/* static variables */
+static int done_init = 0;
+dst_func *dst_t_func[DST_MAX_ALGS];
+const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n";
+const char *dst_path = "";
+
+/* internal I/O functions */
+static DST_KEY *dst_s_read_public_key(const char *in_name,
+ const u_int16_t in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+ u_int16_t in_id, int in_alg);
+static int dst_s_write_public_key(const DST_KEY *key);
+static int dst_s_write_private_key(const DST_KEY *key);
+
+/* internal function to set up data structure */
+static DST_KEY *dst_s_get_key_struct(const char *name, const int alg,
+ const int flags, const int protocol,
+ const int bits);
+
+/*%
+ * dst_init
+ * This function initializes the Digital Signature Toolkit.
+ * Right now, it just checks the DSTKEYPATH environment variable.
+ * Parameters
+ * none
+ * Returns
+ * none
+ */
+void
+dst_init()
+{
+ char *s;
+ int len;
+
+ if (done_init != 0)
+ return;
+ done_init = 1;
+
+ s = getenv("DSTKEYPATH");
+ len = 0;
+ if (s) {
+ struct stat statbuf;
+
+ len = strlen(s);
+ if (len > PATH_MAX) {
+ EREPORT(("%s is longer than %d characters, ignoring\n",
+ s, PATH_MAX));
+ } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+ EREPORT(("%s is not a valid directory\n", s));
+ } else {
+ char *tmp;
+ tmp = (char *) malloc(len + 2);
+ memcpy(tmp, s, len + 1);
+ if (tmp[strlen(tmp) - 1] != '/') {
+ tmp[strlen(tmp) + 1] = 0;
+ tmp[strlen(tmp)] = '/';
+ }
+ dst_path = tmp;
+ }
+ }
+ memset(dst_t_func, 0, sizeof(dst_t_func));
+ /* first one is selected */
+ dst_hmac_md5_init();
+}
+
+/*%
+ * dst_check_algorithm
+ * This function determines if the crypto system for the specified
+ * algorithm is present.
+ * Parameters
+ * alg 1 KEY_RSA
+ * 3 KEY_DSA
+ * 157 KEY_HMAC_MD5
+ * future algorithms TBD and registered with IANA.
+ * Returns
+ * 1 - The algorithm is available.
+ * 0 - The algorithm is not available.
+ */
+int
+dst_check_algorithm(const int alg)
+{
+ return (dst_t_func[alg] != NULL);
+}
+
+/*%
+ * dst_s_get_key_struct
+ * This function allocates key structure and fills in some of the
+ * fields of the structure.
+ * Parameters:
+ * name: the name of the key
+ * alg: the algorithm number
+ * flags: the dns flags of the key
+ * protocol: the dns protocol of the key
+ * bits: the size of the key
+ * Returns:
+ * NULL if error
+ * valid pointer otherwise
+ */
+static DST_KEY *
+dst_s_get_key_struct(const char *name, const int alg, const int flags,
+ const int protocol, const int bits)
+{
+ DST_KEY *new_key = NULL;
+
+ if (dst_check_algorithm(alg)) /*%< make sure alg is available */
+ new_key = (DST_KEY *) malloc(sizeof(*new_key));
+ if (new_key == NULL)
+ return (NULL);
+
+ memset(new_key, 0, sizeof(*new_key));
+ new_key->dk_key_name = strdup(name);
+ if (new_key->dk_key_name == NULL) {
+ free(new_key);
+ return (NULL);
+ }
+ new_key->dk_alg = alg;
+ new_key->dk_flags = flags;
+ new_key->dk_proto = protocol;
+ new_key->dk_KEY_struct = NULL;
+ new_key->dk_key_size = bits;
+ new_key->dk_func = dst_t_func[alg];
+ return (new_key);
+}
+
+/*%
+ * dst_compare_keys
+ * Compares two keys for equality.
+ * Parameters
+ * key1, key2 Two keys to be compared.
+ * Returns
+ * 0 The keys are equal.
+ * non-zero The keys are not equal.
+ */
+
+int
+dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ if (key1 == key2)
+ return (0);
+ if (key1 == NULL || key2 == NULL)
+ return (4);
+ if (key1->dk_alg != key2->dk_alg)
+ return (1);
+ if (key1->dk_key_size != key2->dk_key_size)
+ return (2);
+ if (key1->dk_id != key2->dk_id)
+ return (3);
+ return (key1->dk_func->compare(key1, key2));
+}
+
+/*%
+ * dst_sign_data
+ * An incremental signing function. Data is signed in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * itself is created (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode A bit mask used to specify operation(s) to be performed.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 Add data to digest
+ * SIG_MODE_FINAL 4 Generate signature
+ * from signature
+ * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL
+ * data Data to be signed.
+ * len The length in bytes of data to be signed.
+ * in_key Contains a private key to sign with.
+ * KEY structures should be handled (created, converted,
+ * compared, stored, freed) by the DST.
+ * signature
+ * The location to which the signature will be written.
+ * sig_len Length of the signature field in bytes.
+ * Return
+ * 0 Successfull INIT or Update operation
+ * &gt;0 success FINAL (sign) operation
+ * &lt;0 failure
+ */
+
+int
+dst_sign_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_sign_data()");
+
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func && in_key->dk_func->sign)
+ return (in_key->dk_func->sign(mode, in_key, context, data, len,
+ signature, sig_len));
+ return (UNKNOWN_KEYALG);
+}
+
+/*%
+ * dst_verify_data
+ * An incremental verify function. Data is verified in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * is verified (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode Operations to perform this time.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 add data to digest
+ * SIG_MODE_FINAL 4 verify signature
+ * SIG_MODE_ALL
+ * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL)
+ * data Data to pass through the hash function.
+ * len Length of the data in bytes.
+ * in_key Key for verification.
+ * signature Location of signature.
+ * sig_len Length of the signature in bytes.
+ * Returns
+ * 0 Verify success
+ * Non-Zero Verify Failure
+ */
+
+int
+dst_verify_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_verify_data()");
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL)
+ return (UNSUPPORTED_KEYALG);
+ return (in_key->dk_func->verify(mode, in_key, context, data, len,
+ signature, sig_len));
+}
+
+/*%
+ * dst_read_private_key
+ * Access a private key. First the list of private keys that have
+ * already been read in is searched, then the key accessed on disk.
+ * If the private key can be found, it is returned. If the key cannot
+ * be found, a null pointer is returned. The options specify required
+ * key characteristics. If the private key requested does not have
+ * these characteristics, it will not be read.
+ * Parameters
+ * in_keyname The private key name.
+ * in_id The id of the private key.
+ * options DST_FORCE_READ Read from disk - don't use a previously
+ * read key.
+ * DST_CAN_SIGN The key must be useable for signing.
+ * DST_NO_AUTHEN The key must be useable for authentication.
+ * DST_STANDARD Return any key
+ * Returns
+ * NULL If there is no key found in the current directory or
+ * this key has not been loaded before.
+ * !NULL Success - KEY structure returned.
+ */
+
+DST_KEY *
+dst_read_key(const char *in_keyname, const u_int16_t in_id,
+ const int in_alg, const int type)
+{
+ char keyname[PATH_MAX];
+ DST_KEY *dg_key = NULL, *pubkey = NULL;
+
+ if (!dst_check_algorithm(in_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n",
+ in_alg));
+ return (NULL);
+ }
+ if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0)
+ return (NULL);
+ if (in_keyname == NULL) {
+ EREPORT(("dst_read_private_key(): Null key name passed in\n"));
+ return (NULL);
+ } else if (strlen(in_keyname) >= sizeof(keyname)) {
+ EREPORT(("dst_read_private_key(): keyname too big\n"));
+ return (NULL);
+ } else
+ strcpy(keyname, in_keyname);
+
+ /* before I read in the public key, check if it is allowed to sign */
+ if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL)
+ return (NULL);
+
+ if (type == DST_PUBLIC)
+ return pubkey;
+
+ if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg,
+ pubkey->dk_flags, pubkey->dk_proto,
+ 0)))
+ return (dg_key);
+ /* Fill in private key and some fields in the general key structure */
+ if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id,
+ pubkey->dk_alg) == 0)
+ dg_key = dst_free_key(dg_key);
+
+ (void)dst_free_key(pubkey);
+ return (dg_key);
+}
+
+int
+dst_write_key(const DST_KEY *key, const int type)
+{
+ int pub = 0, priv = 0;
+
+ if (key == NULL)
+ return (0);
+ if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_write_key(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0)
+ return (0);
+
+ if (type & DST_PUBLIC)
+ if ((pub = dst_s_write_public_key(key)) < 0)
+ return (pub);
+ if (type & DST_PRIVATE)
+ if ((priv = dst_s_write_private_key(key)) < 0)
+ return (priv);
+ return (priv+pub);
+}
+
+/*%
+ * dst_write_private_key
+ * Write a private key to disk. The filename will be of the form:
+ * K&lt;key-&gt;dk_name&gt;+&lt;key-&gt;dk_alg+&gt;&lt;key-d&gt;k_id.&gt;&lt;private key suffix&gt;.
+ * If there is already a file with this name, an error is returned.
+ *
+ * Parameters
+ * key A DST managed key structure that contains
+ * all information needed about a key.
+ * Return
+ * &gt;= 0 Correct behavior. Returns length of encoded key value
+ * written to disk.
+ * &lt; 0 error.
+ */
+
+static int
+dst_s_write_private_key(const DST_KEY *key)
+{
+ u_char encoded_block[RAW_KEY_SIZE];
+ char file[PATH_MAX];
+ int len;
+ FILE *fp;
+
+ /* First encode the key into the portable key format */
+ if (key == NULL)
+ return (-1);
+ if (key->dk_KEY_struct == NULL)
+ return (0); /*%< null key has no private key */
+ if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) {
+ EREPORT(("dst_write_private_key(): Unsupported operation %d\n",
+ key->dk_alg));
+ return (-5);
+ } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block,
+ sizeof(encoded_block))) <= 0) {
+ EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len));
+ return (-8);
+ }
+ /* Now I can create the file I want to use */
+ dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg,
+ PRIVATE_KEY, PATH_MAX);
+
+ /* Do not overwrite an existing file */
+ if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+ int nn;
+ if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+ EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+ file, len, nn, errno));
+ fclose(fp);
+ return (-5);
+ }
+ fclose(fp);
+ } else {
+ EREPORT(("dst_write_private_key(): Can not create file %s\n"
+ ,file));
+ return (-6);
+ }
+ memset(encoded_block, 0, len);
+ return (len);
+}
+
+/*%
+*
+ * dst_read_public_key
+ * Read a public key from disk and store in a DST key structure.
+ * Parameters
+ * in_name K&lt;in_name&gt;&lt;in_id&gt;.&lt;public key suffix&gt; is the
+ * filename of the key file to be read.
+ * Returns
+ * NULL If the key does not exist or no name is supplied.
+ * NON-NULL Initialized key structure if the key exists.
+ */
+
+static DST_KEY *
+dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg)
+{
+ int flags, proto, alg, len, dlen;
+ int c;
+ char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace;
+ u_char deckey[RAW_KEY_SIZE];
+ FILE *fp;
+
+ if (in_name == NULL) {
+ EREPORT(("dst_read_public_key(): No key name given\n"));
+ return (NULL);
+ }
+ if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n",
+ in_name, in_id, PUBLIC_KEY));
+ return (NULL);
+ }
+ /*
+ * Open the file and read it's formatted contents up to key
+ * File format:
+ * domain.name [ttl] [IN] KEY &lt;flags&gt; &lt;protocol&gt; &lt;algorithm&gt; &lt;key&gt;
+ * flags, proto, alg stored as decimal (or hex numbers FIXME).
+ * (FIXME: handle parentheses for line continuation.)
+ */
+ if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+ EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+ name));
+ return (NULL);
+ }
+ /* Skip domain name, which ends at first blank */
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ /* Skip blank to get to next field */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+
+ /* Skip optional TTL -- if initial digit, skip whole word. */
+ if (isdigit(c)) {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Skip optional "IN" */
+ if (c == 'I' || c == 'i') {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Locate and skip "KEY" */
+ if (c != 'K' && c != 'k') {
+ EREPORT(("\"KEY\" doesn't appear in file: %s", name));
+ return NULL;
+ }
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ ungetc(c, fp); /*%< return the charcter to the input field */
+ /* Handle hex!! FIXME. */
+
+ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
+ EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
+ ,name));
+ return (NULL);
+ }
+ /* read in the key string */
+ fgets(enckey, sizeof(enckey), fp);
+
+ /* If we aren't at end-of-file, something is wrong. */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ if (!feof(fp)) {
+ EREPORT(("Key too long in file: %s", name));
+ return NULL;
+ }
+ fclose(fp);
+
+ if ((len = strlen(enckey)) <= 0)
+ return (NULL);
+
+ /* discard \n */
+ enckey[--len] = '\0';
+
+ /* remove leading spaces */
+ for (notspace = (char *) enckey; isspace((*notspace)&0xff); len--)
+ notspace++;
+
+ dlen = b64_pton(notspace, deckey, sizeof(deckey));
+ if (dlen < 0) {
+ EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
+ dlen));
+ return (NULL);
+ }
+ /* store key and info in a key structure that is returned */
+/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
+ dlen);*/
+ return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen);
+}
+
+/*%
+ * dst_write_public_key
+ * Write a key to disk in DNS format.
+ * Parameters
+ * key Pointer to a DST key structure.
+ * Returns
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_s_write_public_key(const DST_KEY *key)
+{
+ FILE *fp;
+ char filename[PATH_MAX];
+ u_char out_key[RAW_KEY_SIZE];
+ char enc_key[RAW_KEY_SIZE];
+ int len = 0;
+ int mode;
+
+ memset(out_key, 0, sizeof(out_key));
+ if (key == NULL) {
+ EREPORT(("dst_write_public_key(): No key specified \n"));
+ return (0);
+ } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0)
+ return (0);
+
+ /* Make the filename */
+ if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id,
+ key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) {
+ EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n",
+ key->dk_key_name, key->dk_id, PUBLIC_KEY));
+ return (0);
+ }
+ /* XXX in general this should be a check for symmetric keys */
+ mode = (key->dk_alg == KEY_HMAC_MD5) ? 0600 : 0644;
+ /* create public key file */
+ if ((fp = dst_s_fopen(filename, "w+", mode)) == NULL) {
+ EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+ filename, errno));
+ return (0);
+ }
+ /*write out key first base64 the key data */
+ if (key->dk_flags & DST_EXTEND_FLAG)
+ b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key));
+ else
+ b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key));
+ fprintf(fp, "%s IN KEY %d %d %d %s\n",
+ key->dk_key_name,
+ key->dk_flags, key->dk_proto, key->dk_alg, enc_key);
+ fclose(fp);
+ return (1);
+}
+
+/*%
+ * dst_dnskey_to_public_key
+ * This function converts the contents of a DNS KEY RR into a DST
+ * key structure.
+ * Paramters
+ * len Length of the RDATA of the KEY RR RDATA
+ * rdata A pointer to the the KEY RR RDATA.
+ * in_name Key name to be stored in key structure.
+ * Returns
+ * NULL Failure
+ * NON-NULL Success. Pointer to key structure.
+ * Caller's responsibility to free() it.
+ */
+
+DST_KEY *
+dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len)
+{
+ DST_KEY *key_st;
+ int alg ;
+ int start = DST_KEY_START;
+
+ if (rdata == NULL || len <= DST_KEY_ALG) /*%< no data */
+ return (NULL);
+ alg = (u_int8_t) rdata[DST_KEY_ALG];
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n",
+ alg));
+ return (NULL);
+ }
+
+ if (in_name == NULL)
+ return (NULL);
+
+ if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL)
+ return (NULL);
+
+ key_st->dk_id = dst_s_dns_key_id(rdata, len);
+ key_st->dk_flags = dst_s_get_int16(rdata);
+ key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT];
+ if (key_st->dk_flags & DST_EXTEND_FLAG) {
+ u_int32_t ext_flags;
+ ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]);
+ key_st->dk_flags = key_st->dk_flags | (ext_flags << 16);
+ start += 2;
+ }
+ /*
+ * now point to the begining of the data representing the encoding
+ * of the key
+ */
+ if (key_st->dk_func && key_st->dk_func->from_dns_key) {
+ if (key_st->dk_func->from_dns_key(key_st, &rdata[start],
+ len - start) > 0)
+ return (key_st);
+ } else
+ EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n",
+ alg));
+
+ SAFE_FREE(key_st);
+ return (key_st);
+}
+
+/*%
+ * dst_public_key_to_dnskey
+ * Function to encode a public key into DNS KEY wire format
+ * Parameters
+ * key Key structure to encode.
+ * out_storage Location to write the encoded key to.
+ * out_len Size of the output array.
+ * Returns
+ * <0 Failure
+ * >=0 Number of bytes written to out_storage
+ */
+
+int
+dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage,
+ const int out_len)
+{
+ u_int16_t val;
+ int loc = 0;
+ int enc_len = 0;
+ if (key == NULL)
+ return (-1);
+
+ if (!dst_check_algorithm(key->dk_alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ memset(out_storage, 0, out_len);
+ val = (u_int16_t)(key->dk_flags & 0xffff);
+ dst_s_put_int16(out_storage, val);
+ loc += 2;
+
+ out_storage[loc++] = (u_char) key->dk_proto;
+ out_storage[loc++] = (u_char) key->dk_alg;
+
+ if (key->dk_flags > 0xffff) { /*%< Extended flags */
+ val = (u_int16_t)((key->dk_flags >> 16) & 0xffff);
+ dst_s_put_int16(&out_storage[loc], val);
+ loc += 2;
+ }
+ if (key->dk_KEY_struct == NULL)
+ return (loc);
+ if (key->dk_func && key->dk_func->to_dns_key) {
+ enc_len = key->dk_func->to_dns_key(key,
+ (u_char *) &out_storage[loc],
+ out_len - loc);
+ if (enc_len > 0)
+ return (enc_len + loc);
+ else
+ return (-1);
+ } else
+ EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n",
+ key->dk_alg));
+ return (-1);
+}
+
+/*%
+ * dst_buffer_to_key
+ * Function to encode a string of raw data into a DST key
+ * Parameters
+ * alg The algorithm (HMAC only)
+ * key A pointer to the data
+ * keylen The length of the data
+ * Returns
+ * NULL an error occurred
+ * NON-NULL the DST key
+ */
+DST_KEY *
+dst_buffer_to_key(const char *key_name, /*!< name of the key */
+ const int alg, /*!< algorithm */
+ const int flags, /*!< dns flags */
+ const int protocol, /*!< dns protocol */
+ const u_char *key_buf, /*!< key in dns wire fmt */
+ const int key_len) /*!< size of key */
+{
+
+ DST_KEY *dkey = NULL;
+ int dnslen;
+ u_char dns[2048];
+
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1);
+
+ if (dkey == NULL || dkey->dk_func == NULL ||
+ dkey->dk_func->from_dns_key == NULL)
+ return (dst_free_key(dkey));
+
+ if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) {
+ EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n"));
+ return (dst_free_key(dkey));
+ }
+
+ dnslen = dst_key_to_dnskey(dkey, dns, sizeof(dns));
+ dkey->dk_id = dst_s_dns_key_id(dns, dnslen);
+ return (dkey);
+}
+
+int
+dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len)
+{
+ int len;
+ /* this function will extrac the secret of HMAC into a buffer */
+ if (key == NULL)
+ return (0);
+ if (key->dk_func != NULL && key->dk_func->to_dns_key != NULL) {
+ len = key->dk_func->to_dns_key(key, out_buff, buf_len);
+ if (len < 0)
+ return (0);
+ return (len);
+ }
+ return (0);
+}
+
+/*%
+ * dst_s_read_private_key_file
+ * Function reads in private key from a file.
+ * Fills out the KEY structure.
+ * Parameters
+ * name Name of the key to be read.
+ * pk_key Structure that the key is returned in.
+ * in_id Key identifier (tag)
+ * Return
+ * 1 if everthing works
+ * 0 if there is any problem
+ */
+
+static int
+dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id,
+ int in_alg)
+{
+ int cnt, alg, len, major, minor, file_major, file_minor;
+ int ret, id;
+ char filename[PATH_MAX];
+ u_char in_buff[RAW_KEY_SIZE], *p;
+ FILE *fp;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL || pk_key == NULL) {
+ EREPORT(("dst_read_private_key_file(): No key name given\n"));
+ return (0);
+ }
+ /* Make the filename */
+ if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n",
+ name, in_id, PRIVATE_KEY));
+ return (0);
+ }
+ /* first check if we can find the key file */
+ if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+ EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+ filename, dst_path[0] ? dst_path :
+ (char *) getcwd(NULL, PATH_MAX - 1)));
+ return (0);
+ }
+ /* now read the header info from the file */
+ if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) {
+ fclose(fp);
+ EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n",
+ filename));
+ return (0);
+ }
+ /* decrypt key */
+ fclose(fp);
+ if (memcmp(in_buff, "Private-key-format: v", 20) != 0)
+ goto fail;
+ len = cnt;
+ p = in_buff;
+
+ if (!dst_s_verify_str((const char **) (void *)&p,
+ "Private-key-format: v")) {
+ EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name));
+ goto fail;
+ }
+ /* read in file format */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor);
+ if (file_major < 1) {
+ EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n",
+ file_major, file_minor, name));
+ goto fail;
+ } else if (file_major > major || file_minor > minor)
+ EREPORT((
+ "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n",
+ name, file_major, file_minor));
+
+ while (*p++ != '\n') ; /*%< skip to end of line */
+
+ if (!dst_s_verify_str((const char **) (void *)&p, "Algorithm: "))
+ goto fail;
+
+ if (sscanf((char *)p, "%d", &alg) != 1)
+ goto fail;
+ while (*p++ != '\n') ; /*%< skip to end of line */
+
+ if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name))
+ SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name));
+ pk_key->dk_key_name = (char *) strdup(name);
+
+ /* allocate and fill in key structure */
+ if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL)
+ goto fail;
+
+ ret = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p);
+ if (ret < 0)
+ goto fail;
+
+ dnslen = dst_key_to_dnskey(pk_key, dns, sizeof(dns));
+ id = dst_s_dns_key_id(dns, dnslen);
+
+ /* Make sure the actual key tag matches the input tag used in the filename
+ */
+ if (id != in_id) {
+ EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id));
+ goto fail;
+ }
+ pk_key->dk_id = (u_int16_t) id;
+ pk_key->dk_alg = alg;
+ memset(in_buff, 0, cnt);
+ return (1);
+
+ fail:
+ memset(in_buff, 0, cnt);
+ return (0);
+}
+
+/*%
+ * Generate and store a public/private keypair.
+ * Keys will be stored in formatted files.
+ *
+ * Parameters
+ &
+ *\par name Name of the new key. Used to create key files
+ *\li K&lt;name&gt;+&lt;alg&gt;+&lt;id&gt;.public and K&lt;name&gt;+&lt;alg&gt;+&lt;id&gt;.private.
+ *\par bits Size of the new key in bits.
+ *\par exp What exponent to use:
+ *\li 0 use exponent 3
+ *\li non-zero use Fermant4
+ *\par flags The default value of the DNS Key flags.
+ *\li The DNS Key RR Flag field is defined in RFC2065,
+ * section 3.3. The field has 16 bits.
+ *\par protocol
+ *\li Default value of the DNS Key protocol field.
+ *\li The DNS Key protocol field is defined in RFC2065,
+ * section 3.4. The field has 8 bits.
+ *\par alg What algorithm to use. Currently defined:
+ *\li KEY_RSA 1
+ *\li KEY_DSA 3
+ *\li KEY_HMAC 157
+ *\par out_id The key tag is returned.
+ *
+ * Return
+ *\li NULL Failure
+ *\li non-NULL the generated key pair
+ * Caller frees the result, and its dk_name pointer.
+ */
+DST_KEY *
+dst_generate_key(const char *name, const int bits, const int exp,
+ const int flags, const int protocol, const int alg)
+{
+ DST_KEY *new_key = NULL;
+ int dnslen;
+ u_char dns[2048];
+
+ if (name == NULL)
+ return (NULL);
+
+ if (!dst_check_algorithm(alg)) { /*%< make sure alg is available */
+ EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits);
+ if (new_key == NULL)
+ return (NULL);
+ if (bits == 0) /*%< null key we are done */
+ return (new_key);
+ if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) {
+ EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n",
+ alg));
+ return (dst_free_key(new_key));
+ }
+ if (new_key->dk_func->generate(new_key, exp) <= 0) {
+ EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n",
+ new_key->dk_key_name, new_key->dk_alg,
+ new_key->dk_key_size, exp));
+ return (dst_free_key(new_key));
+ }
+
+ dnslen = dst_key_to_dnskey(new_key, dns, sizeof(dns));
+ if (dnslen != UNSUPPORTED_KEYALG)
+ new_key->dk_id = dst_s_dns_key_id(dns, dnslen);
+ else
+ new_key->dk_id = 0;
+
+ return (new_key);
+}
+
+/*%
+ * Release all data structures pointed to by a key structure.
+ *
+ * Parameters
+ *\li f_key Key structure to be freed.
+ */
+
+DST_KEY *
+dst_free_key(DST_KEY *f_key)
+{
+
+ if (f_key == NULL)
+ return (f_key);
+ if (f_key->dk_func && f_key->dk_func->destroy)
+ f_key->dk_KEY_struct =
+ f_key->dk_func->destroy(f_key->dk_KEY_struct);
+ else {
+ EREPORT(("dst_free_key(): Unknown key alg %d\n",
+ f_key->dk_alg));
+ }
+ if (f_key->dk_KEY_struct) {
+ free(f_key->dk_KEY_struct);
+ f_key->dk_KEY_struct = NULL;
+ }
+ if (f_key->dk_key_name)
+ SAFE_FREE(f_key->dk_key_name);
+ SAFE_FREE(f_key);
+ return (NULL);
+}
+
+/*%
+ * Return the maximim size of signature from the key specified in bytes
+ *
+ * Parameters
+ *\li key
+ *
+ * Returns
+ * \li bytes
+ */
+int
+dst_sig_size(DST_KEY *key) {
+ switch (key->dk_alg) {
+ case KEY_HMAC_MD5:
+ return (16);
+ case KEY_HMAC_SHA1:
+ return (20);
+ case KEY_RSA:
+ return (key->dk_key_size + 7) / 8;
+ case KEY_DSA:
+ return (40);
+ default:
+ EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg));
+ return -1;
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/dst/dst_internal.h b/usr/src/lib/libresolv2_joy/common/dst/dst_internal.h
new file mode 100644
index 0000000000..e9bc6fc08d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/dst/dst_internal.h
@@ -0,0 +1,155 @@
+#ifndef DST_INTERNAL_H
+#define DST_INTERNAL_H
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+#include <limits.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef POSIX_PATH_MAX
+# define PATH_MAX POSIX_PATH_MAX
+# else
+# define PATH_MAX 255 /*%< this is the value of POSIX_PATH_MAX */
+# endif
+#endif
+
+typedef struct dst_key {
+ char *dk_key_name; /*%< name of the key */
+ int dk_key_size; /*%< this is the size of the key in bits */
+ int dk_proto; /*%< what protocols this key can be used for */
+ int dk_alg; /*%< algorithm number from key record */
+ u_int32_t dk_flags; /*%< and the flags of the public key */
+ u_int16_t dk_id; /*%< identifier of the key */
+ void *dk_KEY_struct; /*%< pointer to key in crypto pkg fmt */
+ struct dst_func *dk_func; /*%< point to cryptto pgk specific function table */
+} DST_KEY;
+#define HAS_DST_KEY
+
+#include <isc/dst.h>
+/*
+ * define what crypto systems are supported for RSA,
+ * BSAFE is prefered over RSAREF; only one can be set at any time
+ */
+#if defined(BSAFE) && defined(RSAREF)
+# error "Cannot have both BSAFE and RSAREF defined"
+#endif
+
+/* Declare dst_lib specific constants */
+#define KEY_FILE_FORMAT "1.2"
+
+/* suffixes for key file names */
+#define PRIVATE_KEY "private"
+#define PUBLIC_KEY "key"
+
+/* error handling */
+#ifdef REPORT_ERRORS
+#define EREPORT(str) printf str
+#else
+#define EREPORT(str) (void)0
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) \
+do{if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}} while (0)
+#define SAFE_FREE2(a,s) if (a != NULL && (long)s > 0){memset(a,0, s);free(a); a=NULL;}
+#endif
+
+typedef struct dst_func {
+ int (*sign)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ u_int8_t *signature, const int sig_len);
+ int (*verify)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ const u_int8_t *signature, const int sig_len);
+ int (*compare)(const DST_KEY *key1, const DST_KEY *key2);
+ int (*generate)(DST_KEY *key, int parms);
+ void *(*destroy)(void *key);
+ /* conversion functions */
+ int (*to_dns_key)(const DST_KEY *key, u_int8_t *out,
+ const int out_len);
+ int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+ const int str_len);
+ int (*to_file_fmt)(const DST_KEY *key, char *out,
+ const int out_len);
+ int (*from_file_fmt)(DST_KEY *key, const char *out,
+ const int out_len);
+
+} dst_func;
+
+extern dst_func *dst_t_func[DST_MAX_ALGS];
+extern const char *key_file_fmt_str;
+extern const char *dst_path;
+
+#ifndef DST_HASH_SIZE
+#define DST_HASH_SIZE 20 /*%< RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */
+#endif
+
+int dst_bsafe_init(void);
+
+int dst_rsaref_init(void);
+
+int dst_hmac_md5_init(void);
+
+int dst_cylink_init(void);
+
+int dst_eay_dss_init(void);
+
+/* from higher level support routines */
+int dst_s_calculate_bits( const u_int8_t *str, const int max_bits);
+int dst_s_verify_str( const char **buf, const char *str);
+
+
+/* conversion between dns names and key file names */
+size_t dst_s_filename_length( const char *name, const char *suffix);
+int dst_s_build_filename( char *filename, const char *name,
+ u_int16_t id, int alg, const char *suffix,
+ size_t filename_length);
+
+FILE *dst_s_fopen (const char *filename, const char *mode, int perm);
+
+/*%
+ * read and write network byte order into u_int?_t
+ * all of these should be retired
+ */
+u_int16_t dst_s_get_int16( const u_int8_t *buf);
+void dst_s_put_int16( u_int8_t *buf, const u_int16_t val);
+
+u_int32_t dst_s_get_int32( const u_int8_t *buf);
+void dst_s_put_int32( u_int8_t *buf, const u_int32_t val);
+
+#ifdef DUMP
+# undef DUMP
+# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d)
+#else
+# define DUMP(a,b,c,d)
+#endif
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg);
+
+
+
+#endif /* DST_INTERNAL_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/dst/hmac_link.c b/usr/src/lib/libresolv2_joy/common/dst/hmac_link.c
new file mode 100644
index 0000000000..23925e4269
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/dst/hmac_link.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifdef HMAC_MD5
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/prod/libbind/dst/hmac_link.c,v 1.8 2007/09/24 17:18:25 each Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+/*%
+ * This file contains an implementation of the HMAC-MD5 algorithm.
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include "dst_internal.h"
+
+#ifdef USE_MD5
+# ifndef HAVE_MD5
+# include "md5.h"
+# else
+# ifdef SOLARIS2
+# include <sys/md5.h>
+# endif
+# endif
+# ifndef _MD5_H_
+# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
+# endif
+#endif
+
+#include "port_after.h"
+
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+#define MD5_LEN 16
+
+
+typedef struct hmackey {
+ u_char hk_ipad[64], hk_opad[64];
+} HMAC_Key;
+
+
+/**************************************************************************
+ * dst_hmac_md5_sign
+ * Call HMAC signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * priv_key key to use for signing.
+ * context the context to be used in this digest
+ * data data to be signed.
+ * len length in bytes of data.
+ * signature location to store signature.
+ * sig_len size of the signature location
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ int sign_len = 0;
+ MD5_CTX *ctx = NULL;
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ if (signature == NULL || sig_len < MD5_LEN)
+ return (SIGN_FINAL_FAILURE);
+ MD5Final(signature, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, signature, MD5_LEN);
+ MD5Final(signature, ctx);
+ sign_len = MD5_LEN;
+ SAFE_FREE(ctx);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_verify()
+ * Calls HMAC verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey key to use for verify.
+ * data data signed.
+ * len length in bytes of data.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ MD5_CTX *ctx = NULL;
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ u_char digest[MD5_LEN];
+ if (signature == NULL || key == NULL || sig_len != MD5_LEN)
+ return (VERIFY_FINAL_FAILURE);
+ MD5Final(digest, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, digest, MD5_LEN);
+ MD5Final(digest, ctx);
+
+ SAFE_FREE(ctx);
+ if (memcmp(digest, signature, MD5_LEN) != 0)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/**************************************************************************
+ * dst_buffer_to_hmac_md5
+ * Converts key from raw data to an HMAC Key
+ * This function gets in a pointer to the data
+ * Parameters
+ * hkey the HMAC key to be filled in
+ * key the key in raw format
+ * keylen the length of the key
+ * Return
+ * 0 Success
+ * <0 Failure
+ */
+static int
+dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
+{
+ int i;
+ HMAC_Key *hkey = NULL;
+ MD5_CTX ctx;
+ int local_keylen = keylen;
+ u_char tk[MD5_LEN];
+
+ if (dkey == NULL || key == NULL || keylen < 0)
+ return (-1);
+
+ if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
+ return (-2);
+
+ memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+ memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
+
+ /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
+ if (keylen > HMAC_LEN) {
+ MD5Init(&ctx);
+ MD5Update(&ctx, key, keylen);
+ MD5Final(tk, &ctx);
+ memset((void *) &ctx, 0, sizeof(ctx));
+ key = tk;
+ local_keylen = MD5_LEN;
+ }
+ /* start out by storing key in pads */
+ memcpy(hkey->hk_ipad, key, local_keylen);
+ memcpy(hkey->hk_opad, key, local_keylen);
+
+ /* XOR key with hk_ipad and opad values */
+ for (i = 0; i < HMAC_LEN; i++) {
+ hkey->hk_ipad[i] ^= HMAC_IPAD;
+ hkey->hk_opad[i] ^= HMAC_OPAD;
+ }
+ dkey->dk_key_size = local_keylen;
+ dkey->dk_KEY_struct = (void *) hkey;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_to_file_format
+ * Encodes an HMAC Key into the portable file format.
+ * Parameters
+ * hkey HMAC KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input hkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, i, key_len;
+ u_char key[HMAC_LEN];
+ HMAC_Key *hkey;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (0);
+ /*
+ * Using snprintf() would be so much simpler here.
+ */
+ if (buff == NULL ||
+ buff_len <= (int)(strlen(key_file_fmt_str) +
+ strlen(KEY_FILE_FORMAT) + 4))
+ return (-1); /*%< no OR not enough space in output area */
+ hkey = (HMAC_Key *) dkey->dk_KEY_struct;
+ memset(buff, 0, buff_len); /*%< just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
+
+ bp = buff + strlen(buff);
+
+ memset(key, 0, HMAC_LEN);
+ for (i = 0; i < HMAC_LEN; i++)
+ key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ for (i = HMAC_LEN - 1; i >= 0; i--)
+ if (key[i] != 0)
+ break;
+ key_len = i + 1;
+
+ if (buff_len - (bp - buff) < 6)
+ return (-1);
+ strcat(bp, "Key: ");
+ bp += strlen("Key: ");
+
+ len = b64_ntop(key, key_len, bp, buff_len - (bp - buff));
+ if (len < 0)
+ return (-1);
+ bp += len;
+ if (buff_len - (bp - buff) < 2)
+ return (-1);
+ *(bp++) = '\n';
+ *bp = '\0';
+
+ return (bp - buff);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_from_file_format
+ * Converts contents of a key file into an HMAC key.
+ * Parameters
+ * hkey structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
+ const int buff_len)
+{
+ const char *p = buff, *eol;
+ u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode
+ * it should probably be fixed rather than doing
+ * this
+ */
+ u_char *tmp;
+ int key_len, len;
+
+ if (dkey == NULL)
+ return (-2);
+ if (buff == NULL || buff_len < 0)
+ return (-1);
+
+ memset(key, 0, sizeof(key));
+
+ if (!dst_s_verify_str(&p, "Key: "))
+ return (-3);
+
+ eol = strchr(p, '\n');
+ if (eol == NULL)
+ return (-4);
+ len = eol - p;
+ tmp = malloc(len + 2);
+ if (tmp == NULL)
+ return (-5);
+ memcpy(tmp, p, len);
+ *(tmp + len) = 0x0;
+ key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /*%< see above */
+ SAFE_FREE2(tmp, len + 2);
+
+ if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
+ return (-6);
+ }
+ return (0);
+}
+
+/*%
+ * dst_hmac_md5_to_dns_key()
+ * function to extract hmac key from DST_KEY structure
+ * intput:
+ * in_key: HMAC-MD5 key
+ * output:
+ * out_str: buffer to write ot
+ * out_len: size of output buffer
+ * returns:
+ * number of bytes written to output buffer
+ */
+static int
+dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+
+ HMAC_Key *hkey;
+ int i;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= in_key->dk_key_size || out_str == NULL)
+ return (-1);
+
+ hkey = (HMAC_Key *) in_key->dk_KEY_struct;
+ for (i = 0; i < in_key->dk_key_size; i++)
+ out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ return (i);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
+ HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
+ return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_free_key_structure
+ * Frees all (none) dynamically allocated structures in hkey
+ */
+
+static void *
+dst_hmac_md5_free_key_structure(void *key)
+{
+ HMAC_Key *hkey = key;
+ SAFE_FREE(hkey);
+ return (NULL);
+}
+
+
+/***************************************************************************
+ * dst_hmac_md5_generate_key
+ * Creates a HMAC key of size size with a maximum size of 63 bytes
+ * generating a HMAC key larger than 63 bytes makes no sense as that key
+ * is digested before use.
+ */
+
+static int
+dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
+{
+ (void)key;
+ (void)nothing;
+ return (-1);
+}
+
+/*%
+ * dst_hmac_md5_init() Function to answer set up function pointers for HMAC
+ * related functions
+ */
+int
+dst_hmac_md5_init()
+{
+ if (dst_t_func[KEY_HMAC_MD5] != NULL)
+ return (1);
+ dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_HMAC_MD5] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
+ dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
+ dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
+ dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
+ dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
+ dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
+ dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
+ dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
+ dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
+ return (1);
+}
+
+#else
+#define dst_hmac_md5_init __dst_hmac_md5_init
+
+int
+dst_hmac_md5_init(){
+ return (0);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/dst/support.c b/usr/src/lib/libresolv2_joy/common/dst/support.c
new file mode 100644
index 0000000000..8f827667d6
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/dst/support.c
@@ -0,0 +1,342 @@
+static const char rcsid[] = "$Header: /proj/cvs/prod/libbind/dst/support.c,v 1.6 2005/10/11 00:10:13 marka Exp $";
+
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include "dst_internal.h"
+
+#include "port_after.h"
+
+/*%
+ * dst_s_verify_str()
+ * Validate that the input string(*str) is at the head of the input
+ * buffer(**buf). If so, move the buffer head pointer (*buf) to
+ * the first byte of data following the string(*str).
+ * Parameters
+ * buf Input buffer.
+ * str Input string.
+ * Return
+ * 0 *str is not the head of **buff
+ * 1 *str is the head of **buff, *buf is is advanced to
+ * the tail of **buf.
+ */
+
+int
+dst_s_verify_str(const char **buf, const char *str)
+{
+ int b, s;
+ if (*buf == NULL) /*%< error checks */
+ return (0);
+ if (str == NULL || *str == '\0')
+ return (1);
+
+ b = strlen(*buf); /*%< get length of strings */
+ s = strlen(str);
+ if (s > b || strncmp(*buf, str, s)) /*%< check if same */
+ return (0); /*%< not a match */
+ (*buf) += s; /*%< advance pointer */
+ return (1);
+}
+
+/*%
+ * dst_s_calculate_bits
+ * Given a binary number represented in a u_char[], determine
+ * the number of significant bits used.
+ * Parameters
+ * str An input character string containing a binary number.
+ * max_bits The maximum possible significant bits.
+ * Return
+ * N The number of significant bits in str.
+ */
+
+int
+dst_s_calculate_bits(const u_char *str, const int max_bits)
+{
+ const u_char *p = str;
+ u_char i, j = 0x80;
+ int bits;
+ for (bits = max_bits; *p == 0x00 && bits > 0; p++)
+ bits -= 8;
+ for (i = *p; (i & j) != j; j >>= 1)
+ bits--;
+ return (bits);
+}
+
+/*%
+ * calculates a checksum used in dst for an id.
+ * takes an array of bytes and a length.
+ * returns a 16 bit checksum.
+ */
+u_int16_t
+dst_s_id_calc(const u_char *key, const int keysize)
+{
+ u_int32_t ac;
+ const u_char *kp = key;
+ int size = keysize;
+
+ if (!key || (keysize <= 0))
+ return (0xffffU);
+
+ for (ac = 0; size > 1; size -= 2, kp += 2)
+ ac += ((*kp) << 8) + *(kp + 1);
+
+ if (size > 0)
+ ac += ((*kp) << 8);
+ ac += (ac >> 16) & 0xffff;
+
+ return (ac & 0xffff);
+}
+
+/*%
+ * dst_s_dns_key_id() Function to calculate DNSSEC footprint from KEY record
+ * rdata
+ * Input:
+ * dns_key_rdata: the raw data in wire format
+ * rdata_len: the size of the input data
+ * Output:
+ * the key footprint/id calculated from the key data
+ */
+u_int16_t
+dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len)
+{
+ if (!dns_key_rdata)
+ return 0;
+
+ /* compute id */
+ if (dns_key_rdata[3] == KEY_RSA) /*%< Algorithm RSA */
+ return dst_s_get_int16((const u_char *)
+ &dns_key_rdata[rdata_len - 3]);
+ else if (dns_key_rdata[3] == KEY_HMAC_MD5)
+ /* compatibility */
+ return 0;
+ else
+ /* compute a checksum on the key part of the key rr */
+ return dst_s_id_calc(dns_key_rdata, rdata_len);
+}
+
+/*%
+ * dst_s_get_int16
+ * This routine extracts a 16 bit integer from a two byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A two byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int16_t
+dst_s_get_int16(const u_char *buf)
+{
+ register u_int16_t a = 0;
+ a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
+ return (a);
+}
+
+/*%
+ * dst_s_get_int32
+ * This routine extracts a 32 bit integer from a four byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A four byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int32_t
+dst_s_get_int32(const u_char *buf)
+{
+ register u_int32_t a = 0;
+ a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
+ ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
+ return (a);
+}
+
+/*%
+ * dst_s_put_int16
+ * Take a 16 bit integer and store the value in a two byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a two byte character string.
+ * val 16 bit integer.
+ */
+
+void
+dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
+{
+ buf[0] = (u_int8_t)(val >> 8);
+ buf[1] = (u_int8_t)(val);
+}
+
+/*%
+ * dst_s_put_int32
+ * Take a 32 bit integer and store the value in a four byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a four byte character string.
+ * val 32 bit integer.
+ */
+
+void
+dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
+{
+ buf[0] = (u_int8_t)(val >> 24);
+ buf[1] = (u_int8_t)(val >> 16);
+ buf[2] = (u_int8_t)(val >> 8);
+ buf[3] = (u_int8_t)(val);
+}
+
+/*%
+ * dst_s_filename_length
+ *
+ * This function returns the number of bytes needed to hold the
+ * filename for a key file. '/', '\' and ':' are not allowed.
+ * form: K&lt;keyname&gt;+&lt;alg&gt;+&lt;id&gt;.&lt;suffix&gt;
+ *
+ * Returns 0 if the filename would contain either '\', '/' or ':'
+ */
+size_t
+dst_s_filename_length(const char *name, const char *suffix)
+{
+ if (name == NULL)
+ return (0);
+ if (strrchr(name, '\\'))
+ return (0);
+ if (strrchr(name, '/'))
+ return (0);
+ if (strrchr(name, ':'))
+ return (0);
+ if (suffix == NULL)
+ return (0);
+ if (strrchr(suffix, '\\'))
+ return (0);
+ if (strrchr(suffix, '/'))
+ return (0);
+ if (strrchr(suffix, ':'))
+ return (0);
+ return (1 + strlen(name) + 6 + strlen(suffix));
+}
+
+/*%
+ * dst_s_build_filename ()
+ * Builds a key filename from the key name, it's id, and a
+ * suffix. '\', '/' and ':' are not allowed. fA filename is of the
+ * form: K&lt;keyname&gt;&lt;id&gt;.&lt;suffix&gt;
+ * form: K&lt;keyname&gt;+&lt;alg&gt;+&lt;id&gt;.&lt;suffix&gt;
+ *
+ * Returns -1 if the conversion fails:
+ * if the filename would be too long for space allotted
+ * if the filename would contain a '\', '/' or ':'
+ * Returns 0 on success
+ */
+
+int
+dst_s_build_filename(char *filename, const char *name, u_int16_t id,
+ int alg, const char *suffix, size_t filename_length)
+{
+ u_int32_t my_id;
+ if (filename == NULL)
+ return (-1);
+ memset(filename, 0, filename_length);
+ if (name == NULL)
+ return (-1);
+ if (suffix == NULL)
+ return (-1);
+ if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
+ return (-1);
+ my_id = id;
+ sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
+ (const char *) suffix);
+ if (strrchr(filename, '/'))
+ return (-1);
+ if (strrchr(filename, '\\'))
+ return (-1);
+ if (strrchr(filename, ':'))
+ return (-1);
+ return (0);
+}
+
+/*%
+ * dst_s_fopen ()
+ * Open a file in the dst_path directory. If perm is specified, the
+ * file is checked for existence first, and not opened if it exists.
+ * Parameters
+ * filename File to open
+ * mode Mode to open the file (passed directly to fopen)
+ * perm File permission, if creating a new file.
+ * Returns
+ * NULL Failure
+ * NON-NULL (FILE *) of opened file.
+ */
+FILE *
+dst_s_fopen(const char *filename, const char *mode, int perm)
+{
+ FILE *fp;
+ char pathname[PATH_MAX];
+
+ if (strlen(filename) + strlen(dst_path) >= sizeof(pathname))
+ return (NULL);
+
+ if (*dst_path != '\0') {
+ strcpy(pathname, dst_path);
+ strcat(pathname, filename);
+ } else
+ strcpy(pathname, filename);
+
+ fp = fopen(pathname, mode);
+ if (perm)
+ chmod(pathname, perm);
+ return (fp);
+}
+
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg)
+{
+ UNUSED(data);
+
+ if (size > 0) {
+#ifdef LONG_TEST
+ static u_char scratch[1000];
+ int n ;
+ n = b64_ntop(data, scratch, size, sizeof(scratch));
+ printf("%s: %x %d %s\n", msg, mode, n, scratch);
+#else
+ printf("%s,%x %d\n", msg, mode, size);
+#endif
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_ntop.c b/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_ntop.c
new file mode 100644
index 0000000000..bf960a8acc
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_ntop.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
+
+/*%
+ * char *
+ * inet_cidr_ntop(af, src, bits, dst, size)
+ * convert network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_ntop() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+char *
+inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_cidr_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+static int
+decoct(const u_char *src, int bytes, char *dst, size_t size) {
+ char *odst = dst;
+ char *t;
+ int b;
+
+ for (b = 1; b <= bytes; b++) {
+ if (size < sizeof "255.")
+ return (0);
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b != bytes) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+ return (dst - odst);
+}
+
+/*%
+ * static char *
+ * inet_cidr_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
+ char *odst = dst;
+ size_t len = 4;
+ size_t b;
+ size_t bytes;
+
+ if ((bits < -1) || (bits > 32)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Find number of significant bytes in address. */
+ if (bits == -1)
+ len = 4;
+ else
+ for (len = 1, b = 1 ; b < 4U; b++)
+ if (*(src + b))
+ len = b + 1;
+
+ /* Format whole octets plus nonzero trailing octets. */
+ bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
+ if (len > bytes)
+ bytes = len;
+ b = decoct(src, bytes, dst, size);
+ if (b == 0U)
+ goto emsgsize;
+ dst += b;
+ size -= b;
+
+ if (bits != -1) {
+ /* Format CIDR /width. */
+ if (size < sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ }
+
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+static char *
+inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
+ char *tp;
+ struct { int base, len; } best, cur;
+ u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ if ((bits < -1) || (bits > 128)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int n;
+
+ if (src[15] || bits == -1 || bits > 120)
+ n = 4;
+ else if (src[14] || bits > 112)
+ n = 3;
+ else
+ n = 2;
+ n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
+ if (n == 0) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += SPRINTF((tp, "%x", words[i]));
+ }
+
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp = '\0';
+
+ if (bits != -1)
+ tp += SPRINTF((tp, "/%u", bits));
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_pton.c b/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_pton.c
new file mode 100644
index 0000000000..07652af463
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_cidr_pton.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
+ int *bits, int ipv6));
+static int inet_cidr_pton_ipv6 __P((const char *src, u_char *dst,
+ int *bits));
+
+static int getbits(const char *, int ipv6);
+
+/*%
+ * int
+ * inet_cidr_pton(af, src, dst, *bits)
+ * convert network address from presentation to network format.
+ * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
+ * "dst" is assumed large enough for its "af". "bits" is set to the
+ * /CIDR prefix length, which can have defaults (like /32 for IPv4).
+ * return:
+ * -1 if an error occurred (inspect errno; ENOENT means bad format).
+ * 0 if successful conversion occurred.
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_pton() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+int
+inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
+ switch (af) {
+ case AF_INET:
+ return (inet_cidr_pton_ipv4(src, dst, bits, 0));
+ case AF_INET6:
+ return (inet_cidr_pton_ipv6(src, dst, bits));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+static const char digits[] = "0123456789";
+
+static int
+inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
+ const u_char *odst = dst;
+ int n, ch, tmp, bits;
+ size_t size = 4;
+
+ /* Get the mantissa. */
+ while (ch = *src++, (isascii(ch) && isdigit(ch))) {
+ tmp = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ INSIST(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ if (size-- == 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ }
+
+ /* Get the prefix length if any. */
+ bits = -1;
+ if (ch == '/' && dst > odst) {
+ bits = getbits(src, ipv6);
+ if (bits == -2)
+ goto enoent;
+ } else if (ch != '\0')
+ goto enoent;
+
+ /* Prefix length can default to /32 only if all four octets spec'd. */
+ if (bits == -1) {
+ if (dst - odst == 4)
+ bits = ipv6 ? 128 : 32;
+ else
+ goto enoent;
+ }
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+
+ /* If prefix length overspecifies mantissa, life is bad. */
+ if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
+ goto enoent;
+
+ /* Extend address to four octets. */
+ while (size-- > 0U)
+ *dst++ = 0;
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+ int bits;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ bits = -1;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return (0);
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/') {
+ bits = getbits(src, 1);
+ if (bits == -2)
+ goto enoent;
+ break;
+ }
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto emsgsize;
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+
+ *pbits = bits;
+ return (0);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+getbits(const char *src, int ipv6) {
+ int bits = 0;
+ char *cp, ch;
+
+ if (*src == '\0') /*%< syntax */
+ return (-2);
+ do {
+ ch = *src++;
+ cp = strchr(digits, ch);
+ if (cp == NULL) /*%< syntax */
+ return (-2);
+ bits *= 10;
+ bits += cp - digits;
+ if (bits == 0 && *src != '\0') /*%< no leading zeros */
+ return (-2);
+ if (bits > (ipv6 ? 128 : 32)) /*%< range error */
+ return (-2);
+ } while (*src != '\0');
+
+ return (bits);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_data.c b/usr/src/lib/libresolv2_joy/common/inet/inet_data.c
new file mode 100644
index 0000000000..58b8c4342d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_data.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: inet_data.c,v 1.4 2005/04/27 04:56:19 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+const struct in6_addr isc_in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr isc_in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_lnaof.c b/usr/src/lib/libresolv2_joy/common/inet/inet_lnaof.c
new file mode 100644
index 0000000000..70ac409512
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_lnaof.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+u_long
+inet_lnaof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i)&IN_CLASSA_HOST);
+ else if (IN_CLASSB(i))
+ return ((i)&IN_CLASSB_HOST);
+ else
+ return ((i)&IN_CLASSC_HOST);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_makeaddr.c b/usr/src/lib/libresolv2_joy/common/inet/inet_makeaddr.c
new file mode 100644
index 0000000000..c56cb3eaeb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_makeaddr.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Formulate an Internet address from network + host. Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+ u_long net, host;
+{
+ struct in_addr a;
+
+ if (net < 128U)
+ a.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+ else if (net < 65536U)
+ a.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+ else if (net < 16777216L)
+ a.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+ else
+ a.s_addr = net | host;
+ a.s_addr = htonl(a.s_addr);
+ return (a);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_net_ntop.c b/usr/src/lib/libresolv2_joy/common/inet/inet_net_ntop.c
new file mode 100644
index 0000000000..fb28e3cbe5
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_net_ntop.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits,
+ char *dst, size_t size));
+static char * inet_net_ntop_ipv6 __P((const u_char *src, int bits,
+ char *dst, size_t size));
+
+/*%
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ * convert network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_net_ntop(af, src, bits, dst, size)
+ int af;
+ const void *src;
+ int bits;
+ char *dst;
+ size_t size;
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_net_ntop_ipv4(src, bits, dst, size));
+ case AF_INET6:
+ return (inet_net_ntop_ipv6(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+static char *
+inet_net_ntop_ipv4(src, bits, dst, size)
+ const u_char *src;
+ int bits;
+ char *dst;
+ size_t size;
+{
+ char *odst = dst;
+ char *t;
+ u_int m;
+ int b;
+
+ if (bits < 0 || bits > 32) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (bits == 0) {
+ if (size < sizeof "0")
+ goto emsgsize;
+ *dst++ = '0';
+ size--;
+ *dst = '\0';
+ }
+
+ /* Format whole octets. */
+ for (b = bits / 8; b > 0; b--) {
+ if (size <= sizeof "255.")
+ goto emsgsize;
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b > 1) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format partial octet. */
+ b = bits % 8;
+ if (b > 0) {
+ if (size <= sizeof ".255")
+ goto emsgsize;
+ t = dst;
+ if (dst != odst)
+ *dst++ = '.';
+ m = ((1 << b) - 1) << (8 - b);
+ dst += SPRINTF((dst, "%u", *src & m));
+ size -= (size_t)(dst - t);
+ }
+
+ /* Format CIDR /width. */
+ if (size <= sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*%
+ * static char *
+ * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
+ * convert IPv6 network number from network to presentation format.
+ * generates CIDR style result always. Picks the shortest representation
+ * unless the IP is really IPv4.
+ * always prints specified number of bits (bits).
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0x11110000 in its fourth octet.
+ * author:
+ * Vadim Kogan (UCB), June 2001
+ * Original version (IPv4) by Paul Vixie (ISC), July 1996
+ */
+
+static char *
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
+ u_int m;
+ int b;
+ int p;
+ int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
+ int i;
+ int is_ipv4 = 0;
+ unsigned char inbuf[16];
+ char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+ char *cp;
+ int words;
+ u_char *s;
+
+ if (bits < 0 || bits > 128) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ cp = outbuf;
+
+ if (bits == 0) {
+ *cp++ = ':';
+ *cp++ = ':';
+ *cp = '\0';
+ } else {
+ /* Copy src to private buffer. Zero host part. */
+ p = (bits + 7) / 8;
+ memcpy(inbuf, src, p);
+ memset(inbuf + p, 0, 16 - p);
+ b = bits % 8;
+ if (b != 0) {
+ m = ~0 << (8 - b);
+ inbuf[p-1] &= m;
+ }
+
+ s = inbuf;
+
+ /* how many words need to be displayed in output */
+ words = (bits + 15) / 16;
+ if (words == 1)
+ words = 2;
+
+ /* Find the longest substring of zero's */
+ zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
+ for (i = 0; i < (words * 2); i += 2) {
+ if ((s[i] | s[i+1]) == 0) {
+ if (tmp_zero_l == 0)
+ tmp_zero_s = i / 2;
+ tmp_zero_l++;
+ } else {
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ tmp_zero_l = 0;
+ }
+ }
+ }
+
+ if (tmp_zero_l && zero_l < tmp_zero_l) {
+ zero_s = tmp_zero_s;
+ zero_l = tmp_zero_l;
+ }
+
+ if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
+ ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
+ ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
+ is_ipv4 = 1;
+
+ /* Format whole words. */
+ for (p = 0; p < words; p++) {
+ if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
+ /* Time to skip some zeros */
+ if (p == zero_s)
+ *cp++ = ':';
+ if (p == words - 1)
+ *cp++ = ':';
+ s++;
+ s++;
+ continue;
+ }
+
+ if (is_ipv4 && p > 5 ) {
+ *cp++ = (p == 6) ? ':' : '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ /* we can potentially drop the last octet */
+ if (p != 7 || bits > 120) {
+ *cp++ = '.';
+ cp += SPRINTF((cp, "%u", *s++));
+ }
+ } else {
+ if (cp != outbuf)
+ *cp++ = ':';
+ cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
+ s += 2;
+ }
+ }
+ }
+ /* Format CIDR /width. */
+ sprintf(cp, "/%u", bits);
+ if (strlen(outbuf) + 1 > size)
+ goto emsgsize;
+ strcpy(dst, outbuf);
+
+ return (dst);
+
+emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_net_pton.c b/usr/src/lib/libresolv2_joy/common/inet/inet_net_pton.c
new file mode 100644
index 0000000000..8d8bfb1f64
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_net_pton.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996, 1998, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * static int
+ * inet_net_pton_ipv4(src, dst, size)
+ * convert IPv4 network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not an IPv4 network specification.
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+static int
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
+ static const char xdigits[] = "0123456789abcdef";
+ static const char digits[] = "0123456789";
+ int n, ch, tmp = 0, dirty, bits;
+ const u_char *odst = dst;
+
+ ch = *src++;
+ if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
+ && isascii((unsigned char)(src[1]))
+ && isxdigit((unsigned char)(src[1]))) {
+ /* Hexadecimal: Eat nybble string. */
+ if (size <= 0U)
+ goto emsgsize;
+ dirty = 0;
+ src++; /*%< skip x or X. */
+ while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
+ if (isupper(ch))
+ ch = tolower(ch);
+ n = strchr(xdigits, ch) - xdigits;
+ INSIST(n >= 0 && n <= 15);
+ if (dirty == 0)
+ tmp = n;
+ else
+ tmp = (tmp << 4) | n;
+ if (++dirty == 2) {
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ dirty = 0;
+ }
+ }
+ if (dirty) { /*%< Odd trailing nybble? */
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) (tmp << 4);
+ }
+ } else if (isascii(ch) && isdigit(ch)) {
+ /* Decimal: eat dotted digit string. */
+ for (;;) {
+ tmp = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ INSIST(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' &&
+ isascii(ch) && isdigit(ch));
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ ch = *src++;
+ if (!isascii(ch) || !isdigit(ch))
+ goto enoent;
+ }
+ } else
+ goto enoent;
+
+ bits = -1;
+ if (ch == '/' && isascii((unsigned char)(src[0])) &&
+ isdigit((unsigned char)(src[0])) && dst > odst) {
+ /* CIDR width specifier. Nothing can follow it. */
+ ch = *src++; /*%< Skip over the /. */
+ bits = 0;
+ do {
+ n = strchr(digits, ch) - digits;
+ INSIST(n >= 0 && n <= 9);
+ bits *= 10;
+ bits += n;
+ if (bits > 32)
+ goto enoent;
+ } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ if (ch != '\0')
+ goto enoent;
+ }
+
+ /* Firey death and destruction unless we prefetched EOS. */
+ if (ch != '\0')
+ goto enoent;
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+ /* If no CIDR spec was given, infer width from net class. */
+ if (bits == -1) {
+ if (*odst >= 240) /*%< Class E */
+ bits = 32;
+ else if (*odst >= 224) /*%< Class D */
+ bits = 8;
+ else if (*odst >= 192) /*%< Class C */
+ bits = 24;
+ else if (*odst >= 128) /*%< Class B */
+ bits = 16;
+ else /*%< Class A */
+ bits = 8;
+ /* If imputed mask is narrower than specified octets, widen. */
+ if (bits < ((dst - odst) * 8))
+ bits = (dst - odst) * 8;
+ /*
+ * If there are no additional bits specified for a class D
+ * address adjust bits to 4.
+ */
+ if (bits == 8 && *odst == 224)
+ bits = 4;
+ }
+ /* Extend network to cover the actual mask. */
+ while (bits > ((dst - odst) * 8)) {
+ if (size-- <= 0U)
+ goto emsgsize;
+ *dst++ = '\0';
+ }
+ return (bits);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static int
+getbits(const char *src, int *bitsp) {
+ static const char digits[] = "0123456789";
+ int n;
+ int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /*%< no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 128) /*%< range */
+ return (0);
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ *bitsp = val;
+ return (1);
+}
+
+static int
+getv4(const char *src, u_char *dst, int *bitsp) {
+ static const char digits[] = "0123456789";
+ u_char *odst = dst;
+ int n;
+ u_int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /*%< no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 255) /*%< range */
+ return (0);
+ continue;
+ }
+ if (ch == '.' || ch == '/') {
+ if (dst - odst > 3) /*%< too many octets? */
+ return (0);
+ *dst++ = val;
+ if (ch == '/')
+ return (getbits(src, bitsp));
+ val = 0;
+ n = 0;
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ if (dst - odst > 3) /*%< too many octets? */
+ return (0);
+ *dst++ = val;
+ return (1);
+}
+
+static int
+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+ int digits;
+ int bits;
+ size_t bytes;
+ int words;
+ int ipv4;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ goto enoent;
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ digits = 0;
+ bits = -1;
+ ipv4 = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++digits > 4)
+ goto enoent;
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ goto enoent;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0')
+ goto enoent;
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ digits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ getv4(curtok, tp, &bits) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ ipv4 = 1;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/' && getbits(src, &bits) > 0)
+ break;
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto enoent;
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (bits == -1)
+ bits = 128;
+
+ words = (bits + 15) / 16;
+ if (words < 2)
+ words = 2;
+ if (ipv4)
+ words = 8;
+ endp = tmp + 2 * words;
+
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ goto enoent;
+
+ bytes = (bits + 7) / 8;
+ if (bytes > size)
+ goto emsgsize;
+ memcpy(dst, tmp, bytes);
+ return (bits);
+
+ enoent:
+ errno = ENOENT;
+ return (-1);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+/*%
+ * int
+ * inet_net_pton(af, src, dst, size)
+ * convert network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not a valid network specification.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(int af, const char *src, void *dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_net_pton_ipv4(src, dst, size));
+ case AF_INET6:
+ return (inet_net_pton_ipv6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_neta.c b/usr/src/lib/libresolv2_joy/common/inet/inet_neta.c
new file mode 100644
index 0000000000..63a6c201a4
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_neta.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_neta.c,v 1.3 2005/04/27 04:56:20 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*%
+ * char *
+ * inet_neta(src, dst, size)
+ * format a u_long network number into presentation format.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * format of ``src'' is as for inet_network().
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_neta(src, dst, size)
+ u_long src;
+ char *dst;
+ size_t size;
+{
+ char *odst = dst;
+ char *tp;
+
+ while (src & 0xffffffff) {
+ u_char b = (src & 0xff000000) >> 24;
+
+ src <<= 8;
+ if (b) {
+ if (size < sizeof "255.")
+ goto emsgsize;
+ tp = dst;
+ dst += SPRINTF((dst, "%u", b));
+ if (src != 0L) {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t)(dst - tp);
+ }
+ }
+ if (dst == odst) {
+ if (size < sizeof "0.0.0.0")
+ goto emsgsize;
+ strcpy(dst, "0.0.0.0");
+ }
+ return (odst);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_netof.c b/usr/src/lib/libresolv2_joy/common/inet/inet_netof.c
new file mode 100644
index 0000000000..c228e3d818
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_netof.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*%
+ * Return the network number from an internet
+ * address; handles class a/b/c network #'s.
+ */
+u_long
+inet_netof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+ else if (IN_CLASSB(i))
+ return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else
+ return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/inet_network.c b/usr/src/lib/libresolv2_joy/common/inet/inet_network.c
new file mode 100644
index 0000000000..47976cff68
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/inet_network.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*%
+ * Internet network address interpretation routine.
+ * The library routines call this routine to interpret
+ * network numbers.
+ */
+u_long
+inet_network(cp)
+ register const char *cp;
+{
+ register u_long val, base, n, i;
+ register char c;
+ u_long parts[4], *pp = parts;
+ int digit;
+
+again:
+ val = 0; base = 10; digit = 0;
+ if (*cp == '0')
+ digit = 1, base = 8, cp++;
+ if (*cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ while ((c = *cp) != 0) {
+ if (isdigit((unsigned char)c)) {
+ if (base == 8U && (c == '8' || c == '9'))
+ return (INADDR_NONE);
+ val = (val * base) + (c - '0');
+ cp++;
+ digit = 1;
+ continue;
+ }
+ if (base == 16U && isxdigit((unsigned char)c)) {
+ val = (val << 4) +
+ (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
+ cp++;
+ digit = 1;
+ continue;
+ }
+ break;
+ }
+ if (!digit)
+ return (INADDR_NONE);
+ if (pp >= parts + 4 || val > 0xffU)
+ return (INADDR_NONE);
+ if (*cp == '.') {
+ *pp++ = val, cp++;
+ goto again;
+ }
+ if (*cp && !isspace(*cp&0xff))
+ return (INADDR_NONE);
+ *pp++ = val;
+ n = pp - parts;
+ if (n > 4U)
+ return (INADDR_NONE);
+ for (val = 0, i = 0; i < n; i++) {
+ val <<= 8;
+ val |= parts[i] & 0xff;
+ }
+ return (val);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/inet/nsap_addr.c b/usr/src/lib/libresolv2_joy/common/inet/nsap_addr.c
new file mode 100644
index 0000000000..a9972e6e32
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/inet/nsap_addr.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv_joy.h>
+#include <resolv_mt.h>
+
+#include "port_after.h"
+
+static char
+xtob(int c) {
+ return (c - (((c >= '0') && (c <= '9')) ? '0' : '7'));
+}
+
+u_int
+inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) {
+ u_char c, nib;
+ u_int len = 0;
+
+ if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X'))
+ return (0);
+ ascii += 2;
+
+ while ((c = *ascii++) != '\0' && len < (u_int)maxlen) {
+ if (c == '.' || c == '+' || c == '/')
+ continue;
+ if (!isascii(c))
+ return (0);
+ if (islower(c))
+ c = toupper(c);
+ if (isxdigit(c)) {
+ nib = xtob(c);
+ c = *ascii++;
+ if (c != '\0') {
+ c = toupper(c);
+ if (isxdigit(c)) {
+ *binary++ = (nib << 4) | xtob(c);
+ len++;
+ } else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ else
+ return (0);
+ }
+ return (len);
+}
+
+char *
+inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
+ int nib;
+ int i;
+ char *tmpbuf = inet_nsap_ntoa_tmpbuf;
+ char *start;
+
+ if (ascii)
+ start = ascii;
+ else {
+ ascii = tmpbuf;
+ start = tmpbuf;
+ }
+
+ *ascii++ = '0';
+ *ascii++ = 'x';
+
+ if (binlen > 255)
+ binlen = 255;
+
+ for (i = 0; i < binlen; i++) {
+ nib = *binary >> 4;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ nib = *binary++ & 0x0f;
+ *ascii++ = nib + (nib < 10 ? '0' : '7');
+ if (((i % 2) == 0 && (i + 1) < binlen))
+ *ascii++ = '.';
+ }
+ *ascii = '\0';
+ return (start);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns.c b/usr/src/lib/libresolv2_joy/common/irs/dns.c
new file mode 100644
index 0000000000..7c50320ae7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * dns.c --- this is the top-level accessor function for the dns
+ */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <resolv_joy.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* forward */
+
+static void dns_close(struct irs_acc *);
+static struct __res_state * dns_res_get(struct irs_acc *);
+static void dns_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* public */
+
+struct irs_acc *
+irs_dns_acc(const char *options) {
+ struct irs_acc *acc;
+ struct dns_p *dns;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(dns = memget(sizeof *dns))) {
+ errno = ENOMEM;
+ memput(acc, sizeof *acc);
+ return (NULL);
+ }
+ memset(dns, 0x5e, sizeof *dns);
+ dns->res = NULL;
+ dns->free_res = NULL;
+ if (hesiod_init(&dns->hes_ctx) < 0) {
+ /*
+ * We allow the dns accessor class to initialize
+ * despite hesiod failing to initialize correctly,
+ * since dns host queries don't depend on hesiod.
+ */
+ dns->hes_ctx = NULL;
+ }
+ acc->private = dns;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_dns_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_dns_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_dns_sv;
+ acc->pr_map = irs_dns_pr;
+ acc->ho_map = irs_dns_ho;
+ acc->nw_map = irs_dns_nw;
+ acc->ng_map = irs_nul_ng;
+ acc->res_get = dns_res_get;
+ acc->res_set = dns_res_set;
+ acc->close = dns_close;
+ return (acc);
+}
+
+/* methods */
+static struct __res_state *
+dns_res_get(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+
+ if (dns->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ dns_res_set(this, res, free);
+ }
+
+ if ((dns->res->options & RES_INIT) == 0U &&
+ res_ninit(dns->res) < 0)
+ return (NULL);
+
+ return (dns->res);
+}
+
+static void
+dns_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+
+ if (dns->res && dns->free_res) {
+ res_nclose(dns->res);
+ (*dns->free_res)(dns->res);
+ }
+ dns->res = res;
+ dns->free_res = free_res;
+}
+
+static void
+dns_close(struct irs_acc *this) {
+ struct dns_p *dns;
+
+ dns = (struct dns_p *)this->private;
+ if (dns->res && dns->free_res)
+ (*dns->free_res)(dns->res);
+ if (dns->hes_ctx)
+ hesiod_end(dns->hes_ctx);
+ memput(dns, sizeof *dns);
+ memput(this, sizeof *this);
+}
+
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns_ho.c b/usr/src/lib/libresolv2_joy/common/irs/dns_ho.c
new file mode 100644
index 0000000000..67812717fb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns_ho.c
@@ -0,0 +1,1143 @@
+/*
+ * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
+/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_ho.c,v 1.23 2008/11/14 02:36:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+
+#define MAXPACKET (65535) /*%< Maximum TCP message size */
+#define BOUNDS_CHECK(ptr, count) \
+ if ((ptr) + (count) > eom) { \
+ had_error++; \
+ continue; \
+ } else (void)0
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+struct dns_res_target {
+ struct dns_res_target *next;
+ querybuf qbuf; /*%< query buffer */
+ u_char *answer; /*%< buffer to put answer */
+ int anslen; /*%< size of answer buffer */
+ int qclass, qtype; /*%< class and type of query */
+ int action; /*%< condition whether query is really issued */
+ char qname[MAXDNAME +1]; /*%< domain name */
+#if 0
+ int n; /*%< result length */
+#endif
+};
+enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};
+enum {RESQRY_SUCCESS, RESQRY_FAIL};
+
+struct pvt {
+ struct hostent host;
+ char * h_addr_ptrs[MAXADDRS + 1];
+ char * host_aliases[MAXALIASES];
+ char hostbuf[8*1024];
+ u_char host_addr[16]; /*%< IPv4 or IPv6 */
+ struct __res_state *res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+/* Note: the IPv6 loopback address is in the "tunnel" space */
+static const u_char v6local[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */
+/* Forwards. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static void map_v4v6_hostent(struct hostent *hp, char **bp,
+ char *ep);
+static void addrsort(res_state, char **, int);
+static struct hostent * gethostans(struct irs_ho *this,
+ const u_char *ansbuf, int anslen,
+ const char *qname, int qtype,
+ int af, int size,
+ struct addrinfo **ret_aip,
+ const struct addrinfo *pai);
+static int add_hostent(struct pvt *pvt, char *bp, char **hap,
+ struct addrinfo *ai);
+static int init(struct irs_ho *this);
+
+/* Exports. */
+
+struct irs_ho *
+irs_dns_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (pvt->res->options & RES_USE_INET6) {
+ hp = ho_byname2(this, name, AF_INET6);
+ if (hp)
+ return (hp);
+ }
+ return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp = NULL;
+ int n, size;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+ struct addrinfo ai;
+ struct dns_res_target *q, *p;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ q = memget(sizeof(*q));
+ if (q == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q));
+
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_A;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ hp = NULL;
+ goto cleanup;
+ }
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_nquery() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+
+ for (p = q; p; p = p->next) {
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = af;
+ if ((hp = gethostans(this, p->answer, n, name, p->qtype,
+ af, size, NULL,
+ (const struct addrinfo *)&ai)) != NULL)
+ goto cleanup; /*%< no more loop is necessary */
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ return(hp);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ const u_char *uaddr = addr;
+ char *qp;
+ struct hostent *hp = NULL;
+ struct addrinfo ai;
+ struct dns_res_target *q, *q2, *p;
+ int n, size, i;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ q = memget(sizeof(*q));
+ q2 = memget(sizeof(*q2));
+ if (q == NULL || q2 == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q));
+ memset(q2, 0, sizeof(*q2));
+
+ if (af == AF_INET6 && len == IN6ADDRSZ &&
+ (!memcmp(uaddr, mapped, sizeof mapped) ||
+ (!memcmp(uaddr, tunnelled, sizeof tunnelled) &&
+ memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) {
+ /* Unmap. */
+ addr = (const char *)addr + sizeof mapped;
+ uaddr += sizeof mapped;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_PTR;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ q->qclass = C_IN;
+ q->qtype = T_PTR;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->next = q2;
+ q->action = RESTGT_DOALWAYS;
+ q2->qclass = C_IN;
+ q2->qtype = T_PTR;
+ q2->answer = q2->qbuf.buf;
+ q2->anslen = sizeof(q2->qbuf);
+ if ((pvt->res->options & RES_NO_NIBBLE2) != 0U)
+ q2->action = RESTGT_IGNORE;
+ else
+ q2->action = RESTGT_AFTERFAILURE;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ if (size > len) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ switch (af) {
+ case AF_INET:
+ qp = q->qname;
+ (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa",
+ (uaddr[3] & 0xff),
+ (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff),
+ (uaddr[0] & 0xff));
+ break;
+ case AF_INET6:
+ if (q->action != RESTGT_IGNORE) {
+ const char *nibsuff = res_get_nibblesuffix(pvt->res);
+ qp = q->qname;
+ for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+ i = SPRINTF((qp, "%x.%x.",
+ uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf));
+ if (i != 4)
+ abort();
+ qp += i;
+ }
+ if (strlen(q->qname) + strlen(nibsuff) + 1 >
+ sizeof q->qname) {
+ errno = ENAMETOOLONG;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ strcpy(qp, nibsuff); /* (checked) */
+ }
+ if (q2->action != RESTGT_IGNORE) {
+ const char *nibsuff2 = res_get_nibblesuffix2(pvt->res);
+ qp = q2->qname;
+ for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+ i = SPRINTF((qp, "%x.%x.",
+ uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf));
+ if (i != 4)
+ abort();
+ qp += i;
+ }
+ if (strlen(q2->qname) + strlen(nibsuff2) + 1 >
+ sizeof q2->qname) {
+ errno = ENAMETOOLONG;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ hp = NULL;
+ goto cleanup;
+ }
+ strcpy(qp, nibsuff2); /* (checked) */
+ }
+ break;
+ default:
+ abort();
+ }
+
+ for (p = q; p; p = p->next) {
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = af;
+ hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size,
+ NULL, (const struct addrinfo *)&ai);
+ if (!hp) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+
+ memcpy(pvt->host_addr, addr, len);
+ pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+ pvt->h_addr_ptrs[1] = NULL;
+ if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) {
+ map_v4v6_address((char*)pvt->host_addr,
+ (char*)pvt->host_addr);
+ pvt->host.h_addrtype = AF_INET6;
+ pvt->host.h_length = IN6ADDRSZ;
+ }
+
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ goto cleanup; /*%< no more loop is necessary. */
+ }
+ hp = NULL; /*%< H_ERRNO was set by subroutines */
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ if (q2 != NULL)
+ memput(q2, sizeof(*q2));
+ return(hp);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+
+ UNUSED(this);
+
+ return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+
+ UNUSED(this);
+
+ /* NOOP */
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+/* XXX */
+extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+ const char *));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int n;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+ struct dns_res_target *q, *q2, *p;
+ struct addrinfo sentinel, *cur;
+ int querystate = RESQRY_FAIL;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ q = memget(sizeof(*q));
+ q2 = memget(sizeof(*q2));
+ if (q == NULL || q2 == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ memset(q, 0, sizeof(*q2));
+ memset(q2, 0, sizeof(*q2));
+
+ switch (pai->ai_family) {
+ case AF_UNSPEC:
+ /* prefer IPv6 */
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->next = q2;
+ q->action = RESTGT_DOALWAYS;
+ q2->qclass = C_IN;
+ q2->qtype = T_A;
+ q2->answer = q2->qbuf.buf;
+ q2->anslen = sizeof(q2->qbuf);
+ q2->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET:
+ q->qclass = C_IN;
+ q->qtype = T_A;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ case AF_INET6:
+ q->qclass = C_IN;
+ q->qtype = T_AAAA;
+ q->answer = q->qbuf.buf;
+ q->anslen = sizeof(q->qbuf);
+ q->action = RESTGT_DOALWAYS;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< better error? */
+ goto cleanup;
+ }
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_nquery() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+
+ for (p = q; p; p = p->next) {
+ struct addrinfo *ai;
+
+ switch(p->action) {
+ case RESTGT_DOALWAYS:
+ break;
+ case RESTGT_AFTERFAILURE:
+ if (querystate == RESQRY_SUCCESS)
+ continue;
+ break;
+ case RESTGT_IGNORE:
+ continue;
+ }
+
+ if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+ p->answer, p->anslen)) < 0) {
+ querystate = RESQRY_FAIL;
+ continue;
+ }
+ (void)gethostans(this, p->answer, n, name, p->qtype,
+ pai->ai_family, /*%< XXX: meaningless */
+ 0, &ai, pai);
+ if (ai) {
+ querystate = RESQRY_SUCCESS;
+ cur->ai_next = ai;
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ querystate = RESQRY_FAIL;
+ }
+
+ cleanup:
+ if (q != NULL)
+ memput(q, sizeof(*q));
+ if (q2 != NULL)
+ memput(q2, sizeof(*q2));
+ return(sentinel.ai_next);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct hostent *
+gethostans(struct irs_ho *this,
+ const u_char *ansbuf, int anslen, const char *qname, int qtype,
+ int af, int size, /*!< meaningless for addrinfo cases */
+ struct addrinfo **ret_aip, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int type, class, ancount, qdcount, n, haveanswer, had_error;
+ int error = NETDB_SUCCESS;
+ int (*name_ok)(const char *);
+ const HEADER *hp;
+ const u_char *eom;
+ const u_char *eor;
+ const u_char *cp;
+ const char *tname;
+ const char *hname;
+ char *bp, *ep, **ap, **hap;
+ char tbuf[MAXDNAME+1];
+ struct addrinfo sentinel, *cur, ai;
+
+ if (pai == NULL) abort();
+ if (ret_aip != NULL)
+ *ret_aip = NULL;
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ tname = qname;
+ eom = ansbuf + anslen;
+ switch (qtype) {
+ case T_A:
+ case T_AAAA:
+ case T_ANY: /*%< use T_ANY only for T_A/T_AAAA lookup */
+ name_ok = res_hnok;
+ break;
+ case T_PTR:
+ name_ok = res_dnok;
+ break;
+ default:
+ abort();
+ }
+
+ pvt->host.h_addrtype = af;
+ pvt->host.h_length = size;
+ hname = pvt->host.h_name = NULL;
+
+ /*
+ * Find first satisfactory answer.
+ */
+ if (ansbuf + HFIXEDSZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ hp = (const HEADER *)ansbuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = pvt->hostbuf;
+ ep = pvt->hostbuf + sizeof(pvt->hostbuf);
+ cp = ansbuf + HFIXEDSZ;
+ if (qdcount != 1) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ cp += n + QFIXEDSZ;
+ if (cp > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
+ /* res_nsend() has already verified that the query name is the
+ * same as the one we sent; this just gets the expanded name
+ * (i.e., with the succeeding search-domain tacked on).
+ */
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ if (n > MAXHOSTNAMELEN) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += n;
+ /* The qname can be abbreviated, but hname is now absolute. */
+ qname = pvt->host.h_name;
+ }
+ ap = pvt->host_aliases;
+ *ap = NULL;
+ pvt->host.h_aliases = pvt->host_aliases;
+ hap = pvt->h_addr_ptrs;
+ *hap = NULL;
+ pvt->host.h_addr_list = pvt->h_addr_ptrs;
+ haveanswer = 0;
+ had_error = 0;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n; /*%< name */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ type = ns_get16(cp);
+ cp += INT16SZ; /*%< type */
+ class = ns_get16(cp);
+ cp += INT16SZ + INT32SZ; /*%< class, TTL */
+ n = ns_get16(cp);
+ cp += INT16SZ; /*%< len */
+ BOUNDS_CHECK(cp, n);
+ if (class != C_IN) {
+ cp += n;
+ continue;
+ }
+ eor = cp + n;
+ if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
+ type == T_CNAME) {
+ if (haveanswer) {
+ int level = LOG_CRIT;
+#ifdef LOG_SECURITY
+ level |= LOG_SECURITY;
+#endif
+ syslog(level,
+ "gethostans: possible attempt to exploit buffer overflow while looking up %s",
+ *qname ? qname : ".");
+ }
+ n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
+ if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ /* Store alias. */
+ if (ap >= &pvt->host_aliases[MAXALIASES-1])
+ continue;
+ *ap++ = bp;
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ bp += n;
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /*%< for the \\0 */
+ if (n > (ep - bp) || n > MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf); /* (checked) */
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_PTR && type == T_CNAME) {
+ n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
+ if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+#ifdef RES_USE_DNAME
+ if ((pvt->res->options & RES_USE_DNAME) != 0U)
+#endif
+ {
+ /*
+ * We may be able to check this regardless
+ * of the USE_DNAME bit, but we add the check
+ * for now since the DNAME support is
+ * experimental.
+ */
+ if (ns_samename(tname, bp) != 1)
+ continue;
+ }
+ /* Get canonical name. */
+ n = strlen(tbuf) + 1; /*%< for the \\0 */
+ if (n > (ep - bp)) {
+ had_error++;
+ continue;
+ }
+ strcpy(bp, tbuf); /* (checked) */
+ tname = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_ANY) {
+ if (!(type == T_A || type == T_AAAA)) {
+ cp += n;
+ continue;
+ }
+ } else if (type != qtype) {
+ cp += n;
+ continue;
+ }
+ switch (type) {
+ case T_PTR:
+ if (ret_aip != NULL) {
+ /* addrinfo never needs T_PTR */
+ cp += n;
+ continue;
+ }
+ if (ns_samename(tname, bp) != 1) {
+ cp += n;
+ continue;
+ }
+ n = dn_expand(ansbuf, eor, cp, bp, ep - bp);
+ if (n < 0 || !maybe_hnok(pvt->res, bp) ||
+ n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ cp += n;
+ if (!haveanswer) {
+ pvt->host.h_name = bp;
+ hname = bp;
+ }
+ else if (ap < &pvt->host_aliases[MAXALIASES-1])
+ *ap++ = bp;
+ else
+ n = -1;
+ if (n != -1) {
+ n = strlen(bp) + 1; /*%< for the \\0 */
+ bp += n;
+ }
+ break;
+ case T_A:
+ case T_AAAA:
+ if (ns_samename(hname, bp) != 1) {
+ cp += n;
+ continue;
+ }
+ if (type == T_A && n != INADDRSZ) {
+ cp += n;
+ continue;
+ }
+ if (type == T_AAAA && n != IN6ADDRSZ) {
+ cp += n;
+ continue;
+ }
+
+ /* make addrinfo. don't overwrite constant PAI */
+ ai = *pai;
+ ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET;
+ cur->ai_next = addr2addrinfo(
+ (const struct addrinfo *)&ai,
+ (const char *)cp);
+ if (cur->ai_next == NULL)
+ had_error++;
+
+ if (!haveanswer) {
+ int nn;
+
+ nn = strlen(bp) + 1; /*%< for the \\0 */
+ if (nn >= MAXHOSTNAMELEN) {
+ cp += n;
+ had_error++;
+ continue;
+ }
+ pvt->host.h_name = bp;
+ hname = bp;
+ bp += nn;
+ }
+ /* Ensure alignment. */
+ bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
+ ~(sizeof(align) - 1));
+ /* Avoid overflows. */
+ if (bp + n > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1]) {
+ had_error++;
+ continue;
+ }
+ if (ret_aip) { /*%< need addrinfo. keep it. */
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else if (cur->ai_next) { /*%< need hostent */
+ struct addrinfo *aip = cur->ai_next;
+
+ for (aip = cur->ai_next; aip;
+ aip = aip->ai_next) {
+ int m;
+
+ m = add_hostent(pvt, bp, hap, aip);
+ if (m < 0) {
+ had_error++;
+ break;
+ }
+ if (m == 0)
+ continue;
+ if (hap < &pvt->h_addr_ptrs[MAXADDRS])
+ hap++;
+ *hap = NULL;
+ bp += m;
+ }
+
+ freeaddrinfo(cur->ai_next);
+ cur->ai_next = NULL;
+ }
+ cp += n;
+ break;
+ default:
+ abort();
+ }
+ if (!had_error)
+ haveanswer++;
+ }
+ if (haveanswer) {
+ if (ret_aip == NULL) {
+ *ap = NULL;
+ *hap = NULL;
+
+ if (pvt->res->nsort && hap != pvt->h_addr_ptrs &&
+ qtype == T_A)
+ addrsort(pvt->res, pvt->h_addr_ptrs,
+ hap - pvt->h_addr_ptrs);
+ if (pvt->host.h_name == NULL) {
+ n = strlen(qname) + 1; /*%< for the \\0 */
+ if (n > (ep - bp) || n >= MAXHOSTNAMELEN)
+ goto no_recovery;
+ strcpy(bp, qname); /* (checked) */
+ pvt->host.h_name = bp;
+ bp += n;
+ }
+ if (pvt->res->options & RES_USE_INET6)
+ map_v4v6_hostent(&pvt->host, &bp, ep);
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (&pvt->host);
+ } else {
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ if (pvt->host.h_name == NULL) {
+ sentinel.ai_next->ai_canonname =
+ strdup(qname);
+ }
+ else {
+ sentinel.ai_next->ai_canonname =
+ strdup(pvt->host.h_name);
+ }
+ }
+ *ret_aip = sentinel.ai_next;
+ return(NULL);
+ }
+ }
+ no_recovery:
+ if (sentinel.ai_next) {
+ /* this should be impossible, but check it for safety */
+ freeaddrinfo(sentinel.ai_next);
+ }
+ if (error == NETDB_SUCCESS)
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ else
+ RES_SET_H_ERRNO(pvt->res, error);
+ return(NULL);
+}
+
+static int
+add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai)
+{
+ int addrlen;
+ char *addrp;
+ const char **tap;
+ char *obp = bp;
+
+ switch(ai->ai_addr->sa_family) {
+ case AF_INET6:
+ addrlen = IN6ADDRSZ;
+ addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+ break;
+ case AF_INET:
+ addrlen = INADDRSZ;
+ addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
+ break;
+ default:
+ return(-1); /*%< abort? */
+ }
+
+ /* Ensure alignment. */
+ bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
+ ~(sizeof(align) - 1));
+ /* Avoid overflows. */
+ if (bp + addrlen > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1])
+ return(-1);
+ if (hap >= &pvt->h_addr_ptrs[MAXADDRS])
+ return(0); /*%< fail, but not treat it as an error. */
+ /* Suppress duplicates. */
+ for (tap = (const char **)pvt->h_addr_ptrs;
+ *tap != NULL;
+ tap++)
+ if (memcmp(*tap, addrp, addrlen) == 0)
+ break;
+ if (*tap != NULL)
+ return (0);
+
+ memcpy(*hap = bp, addrp, addrlen);
+ return((bp + addrlen) - obp);
+}
+
+static void
+map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) {
+ char **ap;
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+ return;
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = IN6ADDRSZ;
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ int i = (u_long)*bpp % sizeof(align);
+
+ if (i != 0)
+ i = sizeof(align) - i;
+
+ if ((ep - *bpp) < (i + IN6ADDRSZ)) {
+ /* Out of memory. Truncate address list here. */
+ *ap = NULL;
+ return;
+ }
+ *bpp += i;
+ map_v4v6_address(*ap, *bpp);
+ *ap = *bpp;
+ *bpp += IN6ADDRSZ;
+ }
+}
+
+static void
+addrsort(res_state statp, char **ap, int num) {
+ int i, j, needsort = 0, aval[MAXADDRS];
+ char **p;
+
+ p = ap;
+ for (i = 0; i < num; i++, p++) {
+ for (j = 0 ; (unsigned)j < statp->nsort; j++)
+ if (statp->sort_list[j].addr.s_addr ==
+ (((struct in_addr *)(*p))->s_addr &
+ statp->sort_list[j].mask))
+ break;
+ aval[i] = j;
+ if (needsort == 0 && i > 0 && j < aval[i-1])
+ needsort = i;
+ }
+ if (!needsort)
+ return;
+
+ while (needsort < num) {
+ for (j = needsort - 1; j >= 0; j--) {
+ if (aval[j] > aval[j+1]) {
+ char *hp;
+
+ i = aval[j];
+ aval[j] = aval[j+1];
+ aval[j+1] = i;
+
+ hp = ap[j];
+ ap[j] = ap[j+1];
+ ap[j+1] = hp;
+
+ } else
+ break;
+ }
+ needsort++;
+ }
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns_nw.c b/usr/src/lib/libresolv2_joy/common/irs/dns_nw.c
new file mode 100644
index 0000000000..e9acfd39c7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns_nw.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_nw.c,v 1.12 2005/04/27 04:56:22 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+
+#define MAXPACKET (64*1024)
+
+struct pvt {
+ struct nwent net;
+ char * ali[MAXALIASES];
+ char buf[BUFSIZ+1];
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ long al;
+ char ac;
+} align;
+
+enum by_what { by_addr, by_name };
+
+/* Forwards. */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static struct nwent * get1101byaddr(struct irs_nw *, u_char *, int);
+static struct nwent * get1101byname(struct irs_nw *, const char *);
+static struct nwent * get1101answer(struct irs_nw *,
+ u_char *ansbuf, int anslen,
+ enum by_what by_what,
+ int af, const char *name,
+ const u_char *addr, int addrlen);
+static struct nwent * get1101mask(struct irs_nw *this, struct nwent *);
+static int make1101inaddr(const u_char *, int, char *, int);
+static void normalize_name(char *name);
+static int init(struct irs_nw *this);
+
+/* Exports. */
+
+struct irs_nw *
+irs_dns_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods. */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ switch (af) {
+ case AF_INET:
+ return (get1101byname(this, name));
+ default:
+ (void)NULL;
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ switch (af) {
+ case AF_INET:
+ return (get1101byaddr(this, net, len));
+ default:
+ (void)NULL;
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = EAFNOSUPPORT;
+ return (NULL);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+
+ UNUSED(this);
+
+ return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct nwent *
+get1101byname(struct irs_nw *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ u_char *ansbuf;
+ int anslen;
+ struct nwent *result;
+
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ anslen = res_nsearch(pvt->res, name, C_IN, T_PTR, ansbuf, MAXPACKET);
+ if (anslen < 0) {
+ memput(ansbuf, MAXPACKET);
+ return (NULL);
+ }
+ result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_name,
+ AF_INET, name, NULL, 0));
+ memput(ansbuf, MAXPACKET);
+ return (result);
+}
+
+static struct nwent *
+get1101byaddr(struct irs_nw *this, u_char *net, int len) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char qbuf[sizeof "255.255.255.255.in-addr.arpa"];
+ struct nwent *result;
+ u_char *ansbuf;
+ int anslen;
+
+ if (len < 1 || len > 32) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
+ return (NULL);
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR, ansbuf, MAXPACKET);
+ if (anslen < 0) {
+ memput(ansbuf, MAXPACKET);
+ return (NULL);
+ }
+ result = get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr,
+ AF_INET, NULL, net, len));
+ memput(ansbuf, MAXPACKET);
+ return (result);
+}
+
+static struct nwent *
+get1101answer(struct irs_nw *this,
+ u_char *ansbuf, int anslen, enum by_what by_what,
+ int af, const char *name, const u_char *addr, int addrlen)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int type, class, ancount, qdcount, haveanswer;
+ char *bp, *ep, **ap;
+ u_char *cp, *eom;
+ HEADER *hp;
+
+ /* Initialize, and parse header. */
+ eom = ansbuf + anslen;
+ if (ansbuf + HFIXEDSZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ hp = (HEADER *)ansbuf;
+ cp = ansbuf + HFIXEDSZ;
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0) {
+ int n = dn_skipname(cp, eom);
+ cp += n + QFIXEDSZ;
+ if (n < 0 || cp > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ }
+ ancount = ntohs(hp->ancount);
+ if (!ancount) {
+ if (hp->aa)
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ else
+ RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+ return (NULL);
+ }
+
+ /* Prepare a return structure. */
+ bp = pvt->buf;
+ ep = pvt->buf + sizeof(pvt->buf);
+ pvt->net.n_name = NULL;
+ pvt->net.n_aliases = pvt->ali;
+ pvt->net.n_addrtype = af;
+ pvt->net.n_addr = NULL;
+ pvt->net.n_length = addrlen;
+
+ /* Save input key if given. */
+ switch (by_what) {
+ case by_name:
+ if (name != NULL) {
+ int n = strlen(name) + 1;
+
+ if (n > (ep - bp)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->net.n_name = strcpy(bp, name); /* (checked) */
+ bp += n;
+ }
+ break;
+ case by_addr:
+ if (addr != NULL && addrlen != 0) {
+ int n = addrlen / 8 + ((addrlen % 8) != 0);
+
+ if (INADDRSZ > (ep - bp)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ memset(bp, 0, INADDRSZ);
+ memcpy(bp, addr, n);
+ pvt->net.n_addr = bp;
+ bp += INADDRSZ;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ /* Parse the answer, collect aliases. */
+ ap = pvt->ali;
+ haveanswer = 0;
+ while (--ancount >= 0 && cp < eom) {
+ int n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+
+ cp += n; /*%< Owner */
+ if (n < 0 || !maybe_dnok(pvt->res, bp) ||
+ cp + 3 * INT16SZ + INT32SZ > eom) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ GETSHORT(type, cp); /*%< Type */
+ GETSHORT(class, cp); /*%< Class */
+ cp += INT32SZ; /*%< TTL */
+ GETSHORT(n, cp); /*%< RDLENGTH */
+ if (class == C_IN && type == T_PTR) {
+ int nn;
+
+ nn = dn_expand(ansbuf, eom, cp, bp, ep - bp);
+ if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ normalize_name(bp);
+ switch (by_what) {
+ case by_addr: {
+ if (pvt->net.n_name == NULL)
+ pvt->net.n_name = bp;
+ else if (ns_samename(pvt->net.n_name, bp) == 1)
+ break;
+ else
+ *ap++ = bp;
+ nn = strlen(bp) + 1;
+ bp += nn;
+ haveanswer++;
+ break;
+ }
+ case by_name: {
+ u_int b1, b2, b3, b4;
+
+ if (pvt->net.n_addr != NULL ||
+ sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
+ &b1, &b2, &b3, &b4) != 4)
+ break;
+ if ((ep - bp) < INADDRSZ) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ return (NULL);
+ }
+ pvt->net.n_addr = bp;
+ *bp++ = b4;
+ *bp++ = b3;
+ *bp++ = b2;
+ *bp++ = b1;
+ pvt->net.n_length = INADDRSZ * 8;
+ haveanswer++;
+ }
+ }
+ }
+ cp += n; /*%< RDATA */
+ }
+ if (!haveanswer) {
+ RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+ return (NULL);
+ }
+ *ap = NULL;
+
+ return (&pvt->net);
+}
+
+static struct nwent *
+get1101mask(struct irs_nw *this, struct nwent *nwent) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME];
+ int anslen, type, class, ancount, qdcount;
+ u_char *ansbuf, *cp, *eom;
+ HEADER *hp;
+
+ if (!nwent)
+ return (NULL);
+ if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
+ < 0) {
+ /* "First, do no harm." */
+ return (nwent);
+ }
+
+ ansbuf = memget(MAXPACKET);
+ if (ansbuf == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ /* Query for the A RR that would hold this network's mask. */
+ anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, MAXPACKET);
+ if (anslen < HFIXEDSZ) {
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+ }
+
+ /* Initialize, and parse header. */
+ hp = (HEADER *)ansbuf;
+ cp = ansbuf + HFIXEDSZ;
+ eom = ansbuf + anslen;
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0) {
+ int n = dn_skipname(cp, eom);
+ cp += n + QFIXEDSZ;
+ if (n < 0 || cp > eom) {
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+ }
+ }
+ ancount = ntohs(hp->ancount);
+
+ /* Parse the answer, collect aliases. */
+ while (--ancount >= 0 && cp < eom) {
+ int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
+
+ if (n < 0 || !maybe_dnok(pvt->res, owner))
+ break;
+ cp += n; /*%< Owner */
+ if (cp + 3 * INT16SZ + INT32SZ > eom)
+ break;
+ GETSHORT(type, cp); /*%< Type */
+ GETSHORT(class, cp); /*%< Class */
+ cp += INT32SZ; /*%< TTL */
+ GETSHORT(n, cp); /*%< RDLENGTH */
+ if (cp + n > eom)
+ break;
+ if (n == INADDRSZ && class == C_IN && type == T_A &&
+ ns_samename(qbuf, owner) == 1) {
+ /* This A RR indicates the actual netmask. */
+ int nn, mm;
+
+ nwent->n_length = 0;
+ for (nn = 0; nn < INADDRSZ; nn++)
+ for (mm = 7; mm >= 0; mm--)
+ if (cp[nn] & (1 << mm))
+ nwent->n_length++;
+ else
+ break;
+ }
+ cp += n; /*%< RDATA */
+ }
+ memput(ansbuf, MAXPACKET);
+ return (nwent);
+}
+
+static int
+make1101inaddr(const u_char *net, int bits, char *name, int size) {
+ int n, m;
+ char *ep;
+
+ ep = name + size;
+
+ /* Zero fill any whole bytes left out of the prefix. */
+ for (n = (32 - bits) / 8; n > 0; n--) {
+ if (ep - name < (int)(sizeof "0."))
+ goto emsgsize;
+ m = SPRINTF((name, "0."));
+ name += m;
+ }
+
+ /* Format the partial byte, if any, within the prefix. */
+ if ((n = bits % 8) != 0) {
+ if (ep - name < (int)(sizeof "255."))
+ goto emsgsize;
+ m = SPRINTF((name, "%u.",
+ net[bits / 8] & ~((1 << (8 - n)) - 1)));
+ name += m;
+ }
+
+ /* Format the whole bytes within the prefix. */
+ for (n = bits / 8; n > 0; n--) {
+ if (ep - name < (int)(sizeof "255."))
+ goto emsgsize;
+ m = SPRINTF((name, "%u.", net[n - 1]));
+ name += m;
+ }
+
+ /* Add the static text. */
+ if (ep - name < (int)(sizeof "in-addr.arpa"))
+ goto emsgsize;
+ (void) SPRINTF((name, "in-addr.arpa"));
+ return (0);
+
+ emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
+
+static void
+normalize_name(char *name) {
+ char *t;
+
+ /* Make lower case. */
+ for (t = name; *t; t++)
+ if (isascii((unsigned char)*t) && isupper((unsigned char)*t))
+ *t = tolower((*t)&0xff);
+
+ /* Remove trailing dots. */
+ while (t > name && t[-1] == '.')
+ *--t = '\0';
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns_p.h b/usr/src/lib/libresolv2_joy/common/irs/dns_p.h
new file mode 100644
index 0000000000..d85ae2a238
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns_p.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: dns_p.h,v 1.4 2005/04/27 04:56:22 sra Exp $
+ */
+
+#ifndef _DNS_P_H_INCLUDED
+#define _DNS_P_H_INCLUDED
+
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+ (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+/*%
+ * Object state.
+ */
+struct dns_p {
+ void *hes_ctx;
+ struct __res_state *res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_dns_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_dns_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_dns_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_dns_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_dns_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_dns_nw __P((struct irs_acc *));
+
+#endif /*_DNS_P_H_INCLUDED*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns_pr.c b/usr/src/lib/libresolv2_joy/common/irs/dns_pr.c
new file mode 100644
index 0000000000..c281be432c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns_pr.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_pr.c,v 1.5 2005/04/27 04:56:22 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+ struct dns_p * dns;
+ struct protoent proto;
+ char * prbuf;
+};
+
+/* Forward. */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static struct protoent * pr_next(struct irs_pr *);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+static struct __res_state * pr_res_get(struct irs_pr *);
+static void pr_res_set(struct irs_pr *,
+ struct __res_state *,
+ void (*)(void *));
+
+static struct protoent * parse_hes_list(struct irs_pr *, char **);
+
+/* Public. */
+
+struct irs_pr *
+irs_dns_pr(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+ struct pvt *pvt;
+ struct irs_pr *pr;
+
+ if (!dns->hes_ctx) {
+ errno = ENODEV;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(pr = memget(sizeof *pr))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x5e, sizeof *pr);
+ pvt->dns = dns;
+ pr->private = pvt;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->close = pr_close;
+ pr->minimize = pr_minimize;
+ pr->res_get = pr_res_get;
+ pr->res_set = pr_res_set;
+ return (pr);
+}
+
+/* Methods. */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->proto.p_aliases)
+ free(pvt->proto.p_aliases);
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct protoent *proto;
+ char **hes_list;
+
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol")))
+ return (NULL);
+
+ proto = parse_hes_list(this, hes_list);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (proto);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int num) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct protoent *proto;
+ char numstr[16];
+ char **hes_list;
+
+ sprintf(numstr, "%d", num);
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum")))
+ return (NULL);
+
+ proto = parse_hes_list(this, hes_list);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (proto);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ UNUSED(this);
+ errno = ENODEV;
+ return (NULL);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state * res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+/* Private. */
+
+static struct protoent *
+parse_hes_list(struct irs_pr *this, char **hes_list) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **cpp, **new;
+ int num = 0;
+ int max = 0;
+
+ for (cpp = hes_list; *cpp; cpp++) {
+ cp = *cpp;
+
+ /* Strip away comments, if any. */
+ if ((p = strchr(cp, '#')))
+ *p = 0;
+
+ /* Skip blank lines. */
+ p = cp;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+
+ /* OK, we've got a live one. Let's parse it for real. */
+ if (pvt->prbuf)
+ free(pvt->prbuf);
+ pvt->prbuf = strdup(cp);
+
+ p = pvt->prbuf;
+ pvt->proto.p_name = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->proto.p_proto = atoi(p);
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+
+ while (*p) {
+ if ((num + 1) >= max || !pvt->proto.p_aliases) {
+ max += 10;
+ new = realloc(pvt->proto.p_aliases,
+ max * sizeof(char *));
+ if (!new) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->proto.p_aliases = new;
+ }
+ pvt->proto.p_aliases[num++] = p;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ }
+ if (!pvt->proto.p_aliases)
+ pvt->proto.p_aliases = malloc(sizeof(char *));
+ if (!pvt->proto.p_aliases)
+ goto cleanup;
+ pvt->proto.p_aliases[num] = NULL;
+ return (&pvt->proto);
+ }
+
+ cleanup:
+ if (pvt->proto.p_aliases) {
+ free(pvt->proto.p_aliases);
+ pvt->proto.p_aliases = NULL;
+ }
+ if (pvt->prbuf) {
+ free(pvt->prbuf);
+ pvt->prbuf = NULL;
+ }
+ return (NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/dns_sv.c b/usr/src/lib/libresolv2_joy/common/irs/dns_sv.c
new file mode 100644
index 0000000000..1001dc1051
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/dns_sv.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_sv.c,v 1.5 2005/04/27 04:56:23 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Definitions */
+
+struct pvt {
+ struct dns_p * dns;
+ struct servent serv;
+ char * svbuf;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward. */
+
+static void sv_close(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *,
+ const char *, const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static struct servent * sv_next(struct irs_sv *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+#ifdef SV_RES_SETGET
+static struct __res_state * sv_res_get(struct irs_sv *);
+static void sv_res_set(struct irs_sv *,
+ struct __res_state *,
+ void (*)(void *));
+#endif
+
+static struct servent * parse_hes_list(struct irs_sv *,
+ char **, const char *);
+
+/* Public */
+
+struct irs_sv *
+irs_dns_sv(struct irs_acc *this) {
+ struct dns_p *dns = (struct dns_p *)this->private;
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if (!dns || !dns->hes_ctx) {
+ errno = ENODEV;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->dns = dns;
+ if (!(sv = memget(sizeof *sv))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ sv->private = pvt;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->next = sv_next;
+ sv->rewind = sv_rewind;
+ sv->close = sv_close;
+ sv->minimize = sv_minimize;
+#ifdef SV_RES_SETGET
+ sv->res_get = sv_res_get;
+ sv->res_set = sv_res_set;
+#else
+ sv->res_get = NULL; /*%< sv_res_get; */
+ sv->res_set = NULL; /*%< sv_res_set; */
+#endif
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->serv.s_aliases)
+ free(pvt->serv.s_aliases);
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct servent *s;
+ char **hes_list;
+
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service")))
+ return (NULL);
+
+ s = parse_hes_list(this, hes_list, proto);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (s);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+ struct servent *s;
+ char portstr[16];
+ char **hes_list;
+
+ sprintf(portstr, "%d", ntohs(port));
+ if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port")))
+ return (NULL);
+
+ s = parse_hes_list(this, hes_list, proto);
+ hesiod_free_list(dns->hes_ctx, hes_list);
+ return (s);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ UNUSED(this);
+ errno = ENODEV;
+ return (NULL);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+/* Private */
+
+static struct servent *
+parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **cpp, **new;
+ int proto_len;
+ int num = 0;
+ int max = 0;
+
+ for (cpp = hes_list; *cpp; cpp++) {
+ cp = *cpp;
+
+ /* Strip away comments, if any. */
+ if ((p = strchr(cp, '#')))
+ *p = 0;
+
+ /* Check to make sure the protocol matches. */
+ p = cp;
+ while (*p && !isspace((unsigned char)*p))
+ p++;
+ if (!*p)
+ continue;
+ if (proto) {
+ proto_len = strlen(proto);
+ if (strncasecmp(++p, proto, proto_len) != 0)
+ continue;
+ if (p[proto_len] && !isspace(p[proto_len]&0xff))
+ continue;
+ }
+ /* OK, we've got a live one. Let's parse it for real. */
+ if (pvt->svbuf)
+ free(pvt->svbuf);
+ pvt->svbuf = strdup(cp);
+
+ p = pvt->svbuf;
+ pvt->serv.s_name = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->serv.s_proto = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (!*p)
+ continue;
+ *p++ = '\0';
+
+ pvt->serv.s_port = htons((u_short) atoi(p));
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (*p)
+ *p++ = '\0';
+
+ while (*p) {
+ if ((num + 1) >= max || !pvt->serv.s_aliases) {
+ max += 10;
+ new = realloc(pvt->serv.s_aliases,
+ max * sizeof(char *));
+ if (!new) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ pvt->serv.s_aliases = new;
+ }
+ pvt->serv.s_aliases[num++] = p;
+ while (*p && !isspace(*p&0xff))
+ p++;
+ if (*p)
+ *p++ = '\0';
+ }
+ if (!pvt->serv.s_aliases)
+ pvt->serv.s_aliases = malloc(sizeof(char *));
+ if (!pvt->serv.s_aliases)
+ goto cleanup;
+ pvt->serv.s_aliases[num] = NULL;
+ return (&pvt->serv);
+ }
+
+ cleanup:
+ if (pvt->serv.s_aliases) {
+ free(pvt->serv.s_aliases);
+ pvt->serv.s_aliases = NULL;
+ }
+ if (pvt->svbuf) {
+ free(pvt->svbuf);
+ pvt->svbuf = NULL;
+ }
+ return (NULL);
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ UNUSED(this);
+ /* NOOP */
+}
+
+#ifdef SV_RES_SETGET
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state * res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct dns_p *dns = pvt->dns;
+
+ __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gai_strerror.c b/usr/src/lib/libresolv2_joy/common/irs/gai_strerror.c
new file mode 100644
index 0000000000..9ca1c4bfe1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gai_strerror.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <port_before.h>
+#include <netdb.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#include <stdlib.h>
+#endif
+
+static const char *gai_errlist[] = {
+ "no error",
+ "address family not supported for name",/*%< EAI_ADDRFAMILY */
+ "temporary failure", /*%< EAI_AGAIN */
+ "invalid flags", /*%< EAI_BADFLAGS */
+ "permanent failure", /*%< EAI_FAIL */
+ "address family not supported", /*%< EAI_FAMILY */
+ "memory failure", /*%< EAI_MEMORY */
+ "no address", /*%< EAI_NODATA */
+ "unknown name or service", /*%< EAI_NONAME */
+ "service not supported for socktype", /*%< EAI_SERVICE */
+ "socktype not supported", /*%< EAI_SOCKTYPE */
+ "system failure", /*%< EAI_SYSTEM */
+ "bad hints", /*%< EAI_BADHINTS */
+ "bad protocol", /*%< EAI_PROTOCOL */
+ "unknown error" /*%< Must be last. */
+};
+
+static const int gai_nerr = (sizeof(gai_errlist)/sizeof(*gai_errlist));
+
+#define EAI_BUFSIZE 128
+
+const char *
+gai_strerror(int ecode) {
+#ifndef DO_PTHREADS
+ static char buf[EAI_BUFSIZE];
+#else /* DO_PTHREADS */
+#ifndef LIBBIND_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+ static pthread_mutex_t lock = LIBBIND_MUTEX_INITIALIZER;
+ static pthread_key_t key;
+ static int once = 0;
+ char *buf;
+#endif
+
+ if (ecode >= 0 && ecode < (gai_nerr - 1))
+ return (gai_errlist[ecode]);
+
+#ifdef DO_PTHREADS
+ if (!once) {
+ if (pthread_mutex_lock(&lock) != 0)
+ goto unknown;
+ if (!once) {
+ if (pthread_key_create(&key, free) != 0) {
+ (void)pthread_mutex_unlock(&lock);
+ goto unknown;
+ }
+ once = 1;
+ }
+ if (pthread_mutex_unlock(&lock) != 0)
+ goto unknown;
+ }
+
+ buf = pthread_getspecific(key);
+ if (buf == NULL) {
+ buf = malloc(EAI_BUFSIZE);
+ if (buf == NULL)
+ goto unknown;
+ if (pthread_setspecific(key, buf) != 0) {
+ free(buf);
+ goto unknown;
+ }
+ }
+#endif
+ /*
+ * XXX This really should be snprintf(buf, EAI_BUFSIZE, ...).
+ * It is safe until message catalogs are used.
+ */
+ sprintf(buf, "%s: %d", gai_errlist[gai_nerr - 1], ecode);
+ return (buf);
+
+#ifdef DO_PTHREADS
+ unknown:
+ return ("unknown error");
+#endif
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen.c b/usr/src/lib/libresolv2_joy/common/irs/gen.c
new file mode 100644
index 0000000000..7da01f5b09
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen.c,v 1.7 2005/04/27 04:56:23 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * this is the top level dispatcher
+ *
+ * The dispatcher is implemented as an accessor class; it is an
+ * accessor class that calls other accessor classes, as controlled by a
+ * configuration file.
+ *
+ * A big difference between this accessor class and others is that the
+ * map class initializers are NULL, and the map classes are already
+ * filled in with method functions that will do the right thing.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+#ifdef SUNW_HOSTS_FALLBACK
+extern int __res_no_hosts_fallback(void);
+#endif /* SUNW_HOSTS_FALLBACK */
+
+/* Definitions */
+
+struct nameval {
+ const char * name;
+ int val;
+};
+
+static const struct nameval acc_names[irs_nacc+1] = {
+ { "local", irs_lcl },
+ { "dns", irs_dns },
+ { "nis", irs_nis },
+ { "irp", irs_irp },
+ { NULL, irs_nacc }
+};
+
+typedef struct irs_acc *(*accinit) __P((const char *options));
+
+static const accinit accs[irs_nacc+1] = {
+ irs_lcl_acc,
+ irs_dns_acc,
+#ifdef WANT_IRS_NIS
+ irs_nis_acc,
+#else
+ NULL,
+#endif
+ irs_irp_acc,
+ NULL
+};
+
+static const struct nameval map_names[irs_nmap+1] = {
+ { "group", irs_gr },
+ { "passwd", irs_pw },
+ { "services", irs_sv },
+ { "protocols", irs_pr },
+ { "hosts", irs_ho },
+ { "networks", irs_nw },
+ { "netgroup", irs_ng },
+ { NULL, irs_nmap }
+};
+
+static const struct nameval option_names[] = {
+ { "merge", IRS_MERGE },
+ { "continue", IRS_CONTINUE },
+ { NULL, 0 }
+};
+
+/* Forward */
+
+static void gen_close(struct irs_acc *);
+static struct __res_state * gen_res_get(struct irs_acc *);
+static void gen_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+static int find_name(const char *, const struct nameval nv[]);
+static void init_map_rules(struct gen_p *, const char *conf_file);
+static struct irs_rule *release_rule(struct irs_rule *);
+static int add_rule(struct gen_p *,
+ enum irs_map_id, enum irs_acc_id,
+ const char *);
+
+/* Public */
+
+struct irs_acc *
+irs_gen_acc(const char *options, const char *conf_file) {
+ struct irs_acc *acc;
+ struct gen_p *irs;
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(irs = memget(sizeof *irs))) {
+ errno = ENOMEM;
+ memput(acc, sizeof *acc);
+ return (NULL);
+ }
+ memset(irs, 0x5e, sizeof *irs);
+ irs->options = strdup(options);
+ irs->res = NULL;
+ irs->free_res = NULL;
+ memset(irs->accessors, 0, sizeof irs->accessors);
+ memset(irs->map_rules, 0, sizeof irs->map_rules);
+ init_map_rules(irs, conf_file);
+ acc->private = irs;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_gen_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_gen_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_gen_sv;
+ acc->pr_map = irs_gen_pr;
+ acc->ho_map = irs_gen_ho;
+ acc->nw_map = irs_gen_nw;
+ acc->ng_map = irs_gen_ng;
+ acc->res_get = gen_res_get;
+ acc->res_set = gen_res_set;
+ acc->close = gen_close;
+ return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+gen_res_get(struct irs_acc *this) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+
+ if (irs->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ gen_res_set(this, res, free);
+ }
+
+ if (((irs->res->options & RES_INIT) == 0U) && res_ninit(irs->res) < 0)
+ return (NULL);
+
+ return (irs->res);
+}
+
+static void
+gen_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+#if 0
+ struct irs_rule *rule;
+ struct irs_ho *ho;
+ struct irs_nw *nw;
+#endif
+
+ if (irs->res && irs->free_res) {
+ res_nclose(irs->res);
+ (*irs->free_res)(irs->res);
+ }
+
+ irs->res = res;
+ irs->free_res = free_res;
+
+#if 0
+ for (rule = irs->map_rules[irs_ho]; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+
+ (*ho->res_set)(ho, res, NULL);
+ }
+ for (rule = irs->map_rules[irs_nw]; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+
+ (*nw->res_set)(nw, res, NULL);
+ }
+#endif
+}
+
+static void
+gen_close(struct irs_acc *this) {
+ struct gen_p *irs = (struct gen_p *)this->private;
+ int n;
+
+ /* Search rules. */
+ for (n = 0; n < irs_nmap; n++)
+ while (irs->map_rules[n] != NULL)
+ irs->map_rules[n] = release_rule(irs->map_rules[n]);
+
+ /* Access methods. */
+ for (n = 0; n < irs_nacc; n++) {
+ /* Map objects. */
+ if (irs->accessors[n].gr != NULL)
+ (*irs->accessors[n].gr->close)(irs->accessors[n].gr);
+ if (irs->accessors[n].pw != NULL)
+ (*irs->accessors[n].pw->close)(irs->accessors[n].pw);
+ if (irs->accessors[n].sv != NULL)
+ (*irs->accessors[n].sv->close)(irs->accessors[n].sv);
+ if (irs->accessors[n].pr != NULL)
+ (*irs->accessors[n].pr->close)(irs->accessors[n].pr);
+ if (irs->accessors[n].ho != NULL)
+ (*irs->accessors[n].ho->close)(irs->accessors[n].ho);
+ if (irs->accessors[n].nw != NULL)
+ (*irs->accessors[n].nw->close)(irs->accessors[n].nw);
+ if (irs->accessors[n].ng != NULL)
+ (*irs->accessors[n].ng->close)(irs->accessors[n].ng);
+ /* Enclosing accessor. */
+ if (irs->accessors[n].acc != NULL)
+ (*irs->accessors[n].acc->close)(irs->accessors[n].acc);
+ }
+
+ /* The options string was strdup'd. */
+ free((void*)irs->options);
+
+ if (irs->res && irs->free_res)
+ (*irs->free_res)(irs->res);
+
+ /* The private data container. */
+ memput(irs, sizeof *irs);
+
+ /* The object. */
+ memput(this, sizeof *this);
+}
+
+/* Private */
+
+static int
+find_name(const char *name, const struct nameval names[]) {
+ int n;
+
+ for (n = 0; names[n].name != NULL; n++)
+ if (strcmp(name, names[n].name) == 0)
+ return (names[n].val);
+ return (-1);
+}
+
+static struct irs_rule *
+release_rule(struct irs_rule *rule) {
+ struct irs_rule *next = rule->next;
+
+ memput(rule, sizeof *rule);
+ return (next);
+}
+
+static int
+add_rule(struct gen_p *irs,
+ enum irs_map_id map, enum irs_acc_id acc,
+ const char *options)
+{
+ struct irs_rule **rules, *last, *tmp, *new;
+ struct irs_inst *inst;
+ const char *cp;
+ int n;
+
+#ifndef WANT_IRS_GR
+ if (map == irs_gr)
+ return (-1);
+#endif
+#ifndef WANT_IRS_PW
+ if (map == irs_pw)
+ return (-1);
+#endif
+#ifndef WANT_IRS_NIS
+ if (acc == irs_nis)
+ return (-1);
+#endif
+ new = memget(sizeof *new);
+ if (new == NULL)
+ return (-1);
+ memset(new, 0x5e, sizeof *new);
+ new->next = NULL;
+
+ new->inst = &irs->accessors[acc];
+
+ new->flags = 0;
+ cp = options;
+ while (cp && *cp) {
+ char option[50], *next;
+
+ next = strchr(cp, ',');
+ if (next)
+ n = next++ - cp;
+ else
+ n = strlen(cp);
+ if ((size_t)n > sizeof option - 1)
+ n = sizeof option - 1;
+ strncpy(option, cp, n);
+ option[n] = '\0';
+
+ n = find_name(option, option_names);
+ if (n >= 0)
+ new->flags |= n;
+
+ cp = next;
+ }
+
+ rules = &irs->map_rules[map];
+ for (last = NULL, tmp = *rules;
+ tmp != NULL;
+ last = tmp, tmp = tmp->next)
+ (void)NULL;
+ if (last == NULL)
+ *rules = new;
+ else
+ last->next = new;
+
+ /* Try to instantiate map accessors for this if necessary & approp. */
+ inst = &irs->accessors[acc];
+ if (inst->acc == NULL && accs[acc] != NULL)
+ inst->acc = (*accs[acc])(irs->options);
+ if (inst->acc != NULL) {
+ if (inst->gr == NULL && inst->acc->gr_map != NULL)
+ inst->gr = (*inst->acc->gr_map)(inst->acc);
+ if (inst->pw == NULL && inst->acc->pw_map != NULL)
+ inst->pw = (*inst->acc->pw_map)(inst->acc);
+ if (inst->sv == NULL && inst->acc->sv_map != NULL)
+ inst->sv = (*inst->acc->sv_map)(inst->acc);
+ if (inst->pr == NULL && inst->acc->pr_map != NULL)
+ inst->pr = (*inst->acc->pr_map)(inst->acc);
+ if (inst->ho == NULL && inst->acc->ho_map != NULL)
+ inst->ho = (*inst->acc->ho_map)(inst->acc);
+ if (inst->nw == NULL && inst->acc->nw_map != NULL)
+ inst->nw = (*inst->acc->nw_map)(inst->acc);
+ if (inst->ng == NULL && inst->acc->ng_map != NULL)
+ inst->ng = (*inst->acc->ng_map)(inst->acc);
+ }
+
+ return (0);
+}
+
+static void
+default_map_rules(struct gen_p *irs) {
+ /* Install time honoured and proved BSD style rules as default. */
+ add_rule(irs, irs_gr, irs_lcl, "");
+ add_rule(irs, irs_pw, irs_lcl, "");
+ add_rule(irs, irs_sv, irs_lcl, "");
+ add_rule(irs, irs_pr, irs_lcl, "");
+#ifdef SUNW_HOSTS_FALLBACK
+ if (__res_no_hosts_fallback())
+ add_rule(irs, irs_ho, irs_dns, "");
+ else {
+ add_rule(irs, irs_ho, irs_dns, "continue");
+ add_rule(irs, irs_ho, irs_lcl, "");
+ }
+#else /* SUNW_HOSTS_FALLBACK */
+ add_rule(irs, irs_ho, irs_dns, "continue");
+ add_rule(irs, irs_ho, irs_lcl, "");
+#endif /* SUNW_HOSTS_FALLBACK */
+ add_rule(irs, irs_nw, irs_dns, "continue");
+ add_rule(irs, irs_nw, irs_lcl, "");
+ add_rule(irs, irs_ng, irs_lcl, "");
+}
+
+static void
+init_map_rules(struct gen_p *irs, const char *conf_file) {
+ char line[1024], pattern[40], mapname[20], accname[20], options[100];
+ FILE *conf;
+
+#ifdef SUNW_HOSTS_FALLBACK
+ if (__res_no_hosts_fallback()) {
+ default_map_rules(irs);
+ return;
+ }
+#endif /* SUNW_HOSTS_FALLBACK */
+
+ if (conf_file == NULL)
+ conf_file = _PATH_IRS_CONF ;
+
+ /* A conf file of "" means compiled in defaults. Irpd wants this */
+ if (conf_file[0] == '\0' || (conf = fopen(conf_file, "r")) == NULL) {
+ default_map_rules(irs);
+ return;
+ }
+ (void) sprintf(pattern, "%%%lus %%%lus %%%lus\n",
+ (unsigned long)sizeof mapname,
+ (unsigned long)sizeof accname,
+ (unsigned long)sizeof options);
+ while (fgets(line, sizeof line, conf)) {
+ enum irs_map_id map;
+ enum irs_acc_id acc;
+ char *tmp;
+ int n;
+
+ for (tmp = line;
+ isascii((unsigned char)*tmp) &&
+ isspace((unsigned char)*tmp);
+ tmp++)
+ (void)NULL;
+ if (*tmp == '#' || *tmp == '\n' || *tmp == '\0')
+ continue;
+ n = sscanf(tmp, pattern, mapname, accname, options);
+ if (n < 2)
+ continue;
+ if (n < 3)
+ options[0] = '\0';
+
+ n = find_name(mapname, map_names);
+ INSIST(n < irs_nmap);
+ if (n < 0)
+ continue;
+ map = (enum irs_map_id) n;
+
+ n = find_name(accname, acc_names);
+ INSIST(n < irs_nacc);
+ if (n < 0)
+ continue;
+ acc = (enum irs_acc_id) n;
+
+ add_rule(irs, map, acc, options);
+ }
+ fclose(conf);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_ho.c b/usr/src/lib/libresolv2_joy/common/irs/gen_ho.c
new file mode 100644
index 0000000000..8e41d7d610
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_ho.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: gen_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct irs_ho * ho;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forwards */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static int init(struct irs_ho *this);
+
+/* Exports */
+
+struct irs_ho *
+irs_gen_ho(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ pvt->rules = accpvt->map_rules[irs_ho];
+ pvt->rule = pvt->rules;
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byname)(ho, name);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * The value TRY_AGAIN can mean that the service
+ * is not available, or just that this particular name
+ * cannot be resolved now. We use the errno ECONNREFUSED
+ * to distinguish. If a lookup sets that errno when
+ * H_ERRNO is TRY_AGAIN, we continue to try other lookup
+ * functions, otherwise we return the TRY_AGAIN error.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byname2)(ho, name, af);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct hostent *rval;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ rval = (*ho->byaddr)(ho, addr, len, af);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *rval;
+ struct irs_ho *ho;
+
+ while (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ rval = (*ho->next)(ho);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ (*ho->rewind)(ho);
+ }
+ }
+ return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ho *ho;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ ho = pvt->rule->inst->ho;
+ (*ho->rewind)(ho);
+ }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ho *ho = rule->inst->ho;
+
+ (*ho->minimize)(ho);
+ }
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ho *ho = rule->inst->ho;
+
+ (*ho->res_set)(ho, pvt->res, NULL);
+ }
+}
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct addrinfo *rval = NULL;
+ struct irs_ho *ho;
+ int therrno = NETDB_INTERNAL;
+ int softerror = 0;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ho = rule->inst->ho;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ errno = 0;
+ if (ho->addrinfo == NULL) /*%< for safety */
+ continue;
+ rval = (*ho->addrinfo)(ho, name, pai);
+ if (rval != NULL)
+ return (rval);
+ if (softerror == 0 &&
+ pvt->res->res_h_errno != HOST_NOT_FOUND &&
+ pvt->res->res_h_errno != NETDB_INTERNAL) {
+ softerror = 1;
+ therrno = pvt->res->res_h_errno;
+ }
+ if (rule->flags & IRS_CONTINUE)
+ continue;
+ /*
+ * See the comments in ho_byname() explaining
+ * the interpretation of TRY_AGAIN and ECONNREFUSED.
+ */
+ if (pvt->res->res_h_errno != TRY_AGAIN ||
+ errno != ECONNREFUSED)
+ break;
+ }
+ if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+ RES_SET_H_ERRNO(pvt->res, therrno);
+ return (NULL);
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ (res_ninit(pvt->res) == -1))
+ return (-1);
+
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_ng.c b/usr/src/lib/libresolv2_joy/common/irs/gen_ng.c
new file mode 100644
index 0000000000..e3c874ee68
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_ng.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_ng.c,v 1.3 2005/04/27 04:56:23 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ char * curgroup;
+};
+
+/* Forward */
+
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_rewind(struct irs_ng *, const char *);
+static void ng_minimize(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_gen_ng(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_ng];
+ pvt->rule = pvt->rules;
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ng_minimize(this);
+ if (pvt->curgroup)
+ free(pvt->curgroup);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ng *ng;
+
+ while (pvt->rule) {
+ ng = pvt->rule->inst->ng;
+ if ((*ng->next)(ng, host, user, domain) == 1)
+ return (1);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ ng = pvt->rule->inst->ng;
+ (*ng->rewind)(ng, pvt->curgroup);
+ }
+ }
+ return (0);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *user, const char *host, const char *domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct irs_ng *ng;
+ int rval;
+
+ rval = 0;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ ng = rule->inst->ng;
+ rval = (*ng->test)(ng, name, user, host, domain);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_ng *ng;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ if (pvt->curgroup)
+ free(pvt->curgroup);
+ pvt->curgroup = strdup(group);
+ ng = pvt->rule->inst->ng;
+ (*ng->rewind)(ng, pvt->curgroup);
+ }
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_ng *ng = rule->inst->ng;
+
+ (*ng->minimize)(ng);
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_nw.c b/usr/src/lib/libresolv2_joy/common/irs/gen_nw.c
new file mode 100644
index 0000000000..12bd0e0f6d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_nw.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_nw.c,v 1.4 2005/04/27 04:56:23 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw*);
+static struct nwent * nw_next(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static int init(struct irs_nw *this);
+
+/* Public */
+
+struct irs_nw *
+irs_gen_nw(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ pvt->rules = accpvt->map_rules[irs_nw];
+ pvt->rule = pvt->rules;
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->next = nw_next;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ while (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ rval = (*nw->next)(nw);
+ if (rval)
+ return (rval);
+ if (!(pvt->rules->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ (*nw->rewind)(nw);
+ }
+ }
+ return (NULL);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ rval = (*nw->byname)(nw, name, type);
+ if (rval != NULL)
+ return (rval);
+ if (pvt->res->res_h_errno != TRY_AGAIN &&
+ !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct nwent *rval;
+ struct irs_nw *nw;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ nw = rule->inst->nw;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ rval = (*nw->byaddr)(nw, net, length, type);
+ if (rval != NULL)
+ return (rval);
+ if (pvt->res->res_h_errno != TRY_AGAIN &&
+ !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_nw *nw;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ nw = pvt->rule->inst->nw;
+ (*nw->rewind)(nw);
+ }
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_nw *nw = rule->inst->nw;
+
+ (*nw->minimize)(nw);
+ }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_nw *nw = rule->inst->nw;
+
+ (*nw->res_set)(nw, pvt->res, NULL);
+ }
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_p.h b/usr/src/lib/libresolv2_joy/common/irs/gen_p.h
new file mode 100644
index 0000000000..1adc5909bb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_p.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: gen_p.h,v 1.3 2005/04/27 04:56:23 sra Exp $
+ */
+
+/*! \file
+ * Notes:
+ * We hope to create a complete set of thread-safe entry points someday,
+ * which will mean a set of getXbyY() functions that take as an argument
+ * a pointer to the map class, which will have a pointer to the private
+ * data, which will be used preferentially to the static variables that
+ * are necessary to support the "classic" interface. This "classic"
+ * interface will then be reimplemented as stubs on top of the thread
+ * safe modules, and will keep the map class pointers as their only
+ * static data. HOWEVER, we are not there yet. So while we will call
+ * the just-barely-converted map class methods with map class pointers,
+ * right now they probably all still use statics. We're not fooling
+ * anybody, and we're not trying to (yet).
+ */
+
+#ifndef _GEN_P_H_INCLUDED
+#define _GEN_P_H_INCLUDED
+
+/*%
+ * These are the access methods.
+ */
+enum irs_acc_id {
+ irs_lcl, /*%< Local. */
+ irs_dns, /*%< DNS or Hesiod. */
+ irs_nis, /*%< Sun NIS ("YP"). */
+ irs_irp, /*%< IR protocol. */
+ irs_nacc
+};
+
+/*%
+ * These are the map types.
+ */
+enum irs_map_id {
+ irs_gr, /*%< "group" */
+ irs_pw, /*%< "passwd" */
+ irs_sv, /*%< "services" */
+ irs_pr, /*%< "protocols" */
+ irs_ho, /*%< "hosts" */
+ irs_nw, /*%< "networks" */
+ irs_ng, /*%< "netgroup" */
+ irs_nmap
+};
+
+/*%
+ * This is an accessor instance.
+ */
+struct irs_inst {
+ struct irs_acc *acc;
+ struct irs_gr * gr;
+ struct irs_pw * pw;
+ struct irs_sv * sv;
+ struct irs_pr * pr;
+ struct irs_ho * ho;
+ struct irs_nw * nw;
+ struct irs_ng * ng;
+};
+
+/*%
+ * This is a search rule for some map type.
+ */
+struct irs_rule {
+ struct irs_rule * next;
+ struct irs_inst * inst;
+ int flags;
+};
+#define IRS_MERGE 0x0001 /*%< Don't stop if acc. has data? */
+#define IRS_CONTINUE 0x0002 /*%< Don't stop if acc. has no data? */
+/*
+ * This is the private data for a search access class.
+ */
+struct gen_p {
+ char * options;
+ struct irs_rule * map_rules[(int)irs_nmap];
+ struct irs_inst accessors[(int)irs_nacc];
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_gen_acc __P((const char *, const char *conf_file));
+extern struct irs_gr * irs_gen_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_gen_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_gen_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_gen_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_gen_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_gen_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_gen_ng __P((struct irs_acc *));
+
+#endif /*_IRS_P_H_INCLUDED*/
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_pr.c b/usr/src/lib/libresolv2_joy/common/irs/gen_pr.c
new file mode 100644
index 0000000000..9fd32c4dd9
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_pr.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_pr.c,v 1.3 2005/04/27 04:56:24 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr*);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+static struct __res_state * pr_res_get(struct irs_pr *);
+static void pr_res_set(struct irs_pr *,
+ struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_pr *
+irs_gen_pr(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x5e, sizeof *pr);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *pr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_pr];
+ pvt->rule = pvt->rules;
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->next = pr_next;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ pr->res_get = pr_res_get;
+ pr->res_set = pr_res_set;
+ return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ while (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ rval = (*pr->next)(pr);
+ if (rval)
+ return (rval);
+ if (!(pvt->rules->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ (*pr->rewind)(pr);
+ }
+ }
+ return (NULL);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pr = rule->inst->pr;
+ rval = (*pr->byname)(pr, name);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct protoent *rval;
+ struct irs_pr *pr;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ pr = rule->inst->pr;
+ rval = (*pr->bynumber)(pr, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_pr *pr;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ pr = pvt->rule->inst->pr;
+ (*pr->rewind)(pr);
+ }
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pr *pr = rule->inst->pr;
+
+ (*pr->minimize)(pr);
+ }
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ pr_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_pr *pr = rule->inst->pr;
+
+ if (pr->res_set)
+ (*pr->res_set)(pr, pvt->res, NULL);
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gen_sv.c b/usr/src/lib/libresolv2_joy/common/irs/gen_sv.c
new file mode 100644
index 0000000000..93b70e57ec
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gen_sv.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_sv.c,v 1.3 2005/04/27 04:56:24 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+ struct irs_rule * rules;
+ struct irs_rule * rule;
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+static struct __res_state * sv_res_get(struct irs_sv *);
+static void sv_res_set(struct irs_sv *,
+ struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_sv *
+irs_gen_sv(struct irs_acc *this) {
+ struct gen_p *accpvt = (struct gen_p *)this->private;
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if (!(sv = memget(sizeof *sv))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->rules = accpvt->map_rules[irs_sv];
+ pvt->rule = pvt->rules;
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+ sv->res_get = sv_res_get;
+ sv->res_set = sv_res_set;
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ while (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ rval = (*sv->next)(sv);
+ if (rval)
+ return (rval);
+ if (!(pvt->rule->flags & IRS_CONTINUE))
+ break;
+ pvt->rule = pvt->rule->next;
+ if (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ (*sv->rewind)(sv);
+ }
+ }
+ return (NULL);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ sv = rule->inst->sv;
+ rval = (*sv->byname)(sv, name, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+ struct servent *rval;
+ struct irs_sv *sv;
+
+ rval = NULL;
+ for (rule = pvt->rules; rule; rule = rule->next) {
+ sv = rule->inst->sv;
+ rval = (*sv->byport)(sv, port, proto);
+ if (rval || !(rule->flags & IRS_CONTINUE))
+ break;
+ }
+ return (rval);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_sv *sv;
+
+ pvt->rule = pvt->rules;
+ if (pvt->rule) {
+ sv = pvt->rule->inst->sv;
+ (*sv->rewind)(sv);
+ }
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_sv *sv = rule->inst->sv;
+
+ (*sv->minimize)(sv);
+ }
+}
+
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ sv_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct irs_rule *rule;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+
+ for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+ struct irs_sv *sv = rule->inst->sv;
+
+ if (sv->res_set)
+ (*sv->res_set)(sv, pvt->res, NULL);
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getaddrinfo.c b/usr/src/lib/libresolv2_joy/common/irs/getaddrinfo.c
new file mode 100644
index 0000000000..19bbbea854
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getaddrinfo.c
@@ -0,0 +1,1253 @@
+/* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ */
+
+/*! \file
+ * Issues to be discussed:
+ *\li Thread safe-ness must be checked.
+ *\li Return values. There are nonstandard return values defined and used
+ * in the source code. This is because RFC2553 is silent about which error
+ * code must be returned for which situation.
+ *\li IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
+ * says to use inet_aton() to convert IPv4 numeric to binary (allows
+ * classful form as a result).
+ * current code - disallow classful form for IPv4 (due to use of inet_pton).
+ *\li freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
+ * invalid.
+ * current code - SEGV on freeaddrinfo(NULL)
+ * Note:
+ *\li We use getipnodebyname() just for thread-safeness. There's no intent
+ * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
+ * getipnodebyname().
+ *\li The code filters out AFs that are not supported by the kernel,
+ * when globbing NULL hostname (to loopback, or wildcard). Is it the right
+ * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
+ * in ai_flags?
+ *\li (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
+ * (1) what should we do against numeric hostname (2) what should we do
+ * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
+ * non-loopback address configured? global address configured?
+ * \par Additional Issue:
+ * To avoid search order issue, we have a big amount of code duplicate
+ * from gethnamaddr.c and some other places. The issues that there's no
+ * lower layer function to lookup "IPv4 or IPv6" record. Calling
+ * gethostbyname2 from getaddrinfo will end up in wrong search order, as
+ * follows:
+ * \li The code makes use of following calls when asked to resolver with
+ * ai_family = PF_UNSPEC:
+ *\code getipnodebyname(host, AF_INET6);
+ * getipnodebyname(host, AF_INET);
+ *\endcode
+ * \li This will result in the following queries if the node is configure to
+ * prefer /etc/hosts than DNS:
+ *\code
+ * lookup /etc/hosts for IPv6 address
+ * lookup DNS for IPv6 address
+ * lookup /etc/hosts for IPv4 address
+ * lookup DNS for IPv4 address
+ *\endcode
+ * which may not meet people's requirement.
+ * \li The right thing to happen is to have underlying layer which does
+ * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
+ * This would result in a bit of code duplicate with _dns_ghbyname() and
+ * friends.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <stdarg.h>
+
+#include <irs.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in_loopback[] = { 127, 0, 0, 1 };
+static const char in6_loopback[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+static const struct afd {
+ int a_af;
+ int a_addrlen;
+ int a_socklen;
+ int a_off;
+ const char *a_addrany;
+ const char *a_loopback;
+ int a_scoped;
+} afdl [] = {
+ {PF_INET6, sizeof(struct in6_addr),
+ sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr),
+ in6_addrany, in6_loopback, 1},
+ {PF_INET, sizeof(struct in_addr),
+ sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr),
+ in_addrany, in_loopback, 0},
+ {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+ int e_af;
+ int e_socktype;
+ int e_protocol;
+ const char *e_protostr;
+ int e_wild;
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+};
+
+static const struct explore explore[] = {
+#if 0
+ { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+#endif
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+ { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
+ { -1, 0, 0, NULL, 0 },
+};
+
+#define PTON_MAX 16
+
+static int str_isnumber __P((const char *));
+static int explore_fqdn __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int explore_copy __P((const struct addrinfo *, const struct addrinfo *,
+ struct addrinfo **));
+static int explore_null __P((const struct addrinfo *,
+ const char *, struct addrinfo **));
+static int explore_numeric __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int explore_numeric_scope __P((const struct addrinfo *, const char *,
+ const char *, struct addrinfo **));
+static int get_canonname __P((const struct addrinfo *,
+ struct addrinfo *, const char *));
+static struct addrinfo *get_ai __P((const struct addrinfo *,
+ const struct afd *, const char *));
+static struct addrinfo *copy_ai __P((const struct addrinfo *));
+static int get_portmatch __P((const struct addrinfo *, const char *));
+static int get_port __P((const struct addrinfo *, const char *, int));
+static const struct afd *find_afd __P((int));
+static int addrconfig __P((int));
+static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *,
+ u_int32_t *scopeidp));
+static struct net_data *init __P((void));
+
+struct addrinfo *hostent2addrinfo __P((struct hostent *,
+ const struct addrinfo *));
+struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+ const char *));
+
+#if 0
+static const char *ai_errlist[] = {
+ "Success",
+ "Address family for hostname not supported", /*%< EAI_ADDRFAMILY */
+ "Temporary failure in name resolution", /*%< EAI_AGAIN */
+ "Invalid value for ai_flags", /*%< EAI_BADFLAGS */
+ "Non-recoverable failure in name resolution", /*%< EAI_FAIL */
+ "ai_family not supported", /*%< EAI_FAMILY */
+ "Memory allocation failure", /*%< EAI_MEMORY */
+ "No address associated with hostname", /*%< EAI_NODATA */
+ "hostname nor servname provided, or not known", /*%< EAI_NONAME */
+ "servname not supported for ai_socktype", /*%< EAI_SERVICE */
+ "ai_socktype not supported", /*%< EAI_SOCKTYPE */
+ "System error returned in errno", /*%< EAI_SYSTEM */
+ "Invalid value for hints", /*%< EAI_BADHINTS */
+ "Resolved protocol is unknown", /*%< EAI_PROTOCOL */
+ "Unknown error", /*%< EAI_MAX */
+};
+#endif
+
+/* XXX macros that make external reference is BAD. */
+
+#define GET_AI(ai, afd, addr) \
+do { \
+ /* external reference: pai, error, and label free */ \
+ (ai) = get_ai(pai, (afd), (addr)); \
+ if ((ai) == NULL) { \
+ error = EAI_MEMORY; \
+ goto free; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define GET_PORT(ai, serv) \
+do { \
+ /* external reference: error and label free */ \
+ error = get_port((ai), (serv), 0); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#define GET_CANONNAME(ai, str) \
+do { \
+ /* external reference: pai, error and label free */ \
+ error = get_canonname(pai, (ai), (str)); \
+ if (error != 0) \
+ goto free; \
+} while (/*CONSTCOND*/0)
+
+#ifndef SOLARIS2
+#define SETERROR(err) \
+do { \
+ /* external reference: error, and label bad */ \
+ error = (err); \
+ goto bad; \
+ /*NOTREACHED*/ \
+} while (/*CONSTCOND*/0)
+#else
+#define SETERROR(err) \
+do { \
+ /* external reference: error, and label bad */ \
+ error = (err); \
+ if (error == error) \
+ goto bad; \
+} while (/*CONSTCOND*/0)
+#endif
+
+
+#define MATCH_FAMILY(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+#define MATCH(x, y, w) \
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+
+#if 0 /*%< bind8 has its own version */
+char *
+gai_strerror(ecode)
+ int ecode;
+{
+ if (ecode < 0 || ecode > EAI_MAX)
+ ecode = EAI_MAX;
+ return ai_errlist[ecode];
+}
+#endif
+
+void
+freeaddrinfo(ai)
+ struct addrinfo *ai;
+{
+ struct addrinfo *next;
+
+ do {
+ next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ /* no need to free(ai->ai_addr) */
+ free(ai);
+ ai = next;
+ } while (ai);
+}
+
+static int
+str_isnumber(p)
+ const char *p;
+{
+ char *ep;
+
+ if (*p == '\0')
+ return NO;
+ ep = NULL;
+ errno = 0;
+ (void)strtoul(p, &ep, 10);
+ if (errno == 0 && ep && *ep == '\0')
+ return YES;
+ else
+ return NO;
+}
+
+int
+getaddrinfo(hostname, servname, hints, res)
+ const char *hostname, *servname;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+{
+ struct addrinfo sentinel;
+ struct addrinfo *cur;
+ int error = 0;
+ struct addrinfo ai, ai0, *afai = NULL;
+ struct addrinfo *pai;
+ const struct explore *ex;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+ pai = &ai;
+ pai->ai_flags = 0;
+ pai->ai_family = PF_UNSPEC;
+ pai->ai_socktype = ANY;
+ pai->ai_protocol = ANY;
+#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
+ /*
+ * clear _ai_pad to preserve binary
+ * compatibility with previously compiled 64-bit
+ * applications in a pre-SUSv3 environment by
+ * guaranteeing the upper 32-bits are empty.
+ */
+ pai->_ai_pad = 0;
+#endif
+ pai->ai_addrlen = 0;
+ pai->ai_canonname = NULL;
+ pai->ai_addr = NULL;
+ pai->ai_next = NULL;
+
+ if (hostname == NULL && servname == NULL)
+ return EAI_NONAME;
+ if (hints) {
+ /* error check for hints */
+ if (hints->ai_addrlen || hints->ai_canonname ||
+ hints->ai_addr || hints->ai_next)
+ SETERROR(EAI_BADHINTS); /*%< xxx */
+ if (hints->ai_flags & ~AI_MASK)
+ SETERROR(EAI_BADFLAGS);
+ switch (hints->ai_family) {
+ case PF_UNSPEC:
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ SETERROR(EAI_FAMILY);
+ }
+ memcpy(pai, hints, sizeof(*pai));
+
+#if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
+ /*
+ * We need to clear _ai_pad to preserve binary
+ * compatibility. See prior comment.
+ */
+ pai->_ai_pad = 0;
+#endif
+ /*
+ * if both socktype/protocol are specified, check if they
+ * are meaningful combination.
+ */
+ if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ if (pai->ai_family != ex->e_af)
+ continue;
+ if (ex->e_socktype == ANY)
+ continue;
+ if (ex->e_protocol == ANY)
+ continue;
+ if (pai->ai_socktype == ex->e_socktype &&
+ pai->ai_protocol != ex->e_protocol) {
+ SETERROR(EAI_BADHINTS);
+ }
+ }
+ }
+ }
+
+ /*
+ * post-2553: AI_ALL and AI_V4MAPPED are effective only against
+ * AF_INET6 query. They needs to be ignored if specified in other
+ * occassions.
+ */
+ switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
+ case AI_V4MAPPED:
+ case AI_ALL | AI_V4MAPPED:
+ if (pai->ai_family != AF_INET6)
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+ case AI_ALL:
+#if 1
+ /* illegal */
+ SETERROR(EAI_BADFLAGS);
+#else
+ pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+ break;
+#endif
+ }
+
+ /*
+ * check for special cases. (1) numeric servname is disallowed if
+ * socktype/protocol are left unspecified. (2) servname is disallowed
+ * for raw and other inet{,6} sockets.
+ */
+ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
+#ifdef PF_INET6
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+ ) {
+ ai0 = *pai; /* backup *pai */
+
+ if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
+ pai->ai_family = PF_INET6;
+#else
+ pai->ai_family = PF_INET;
+#endif
+ }
+ error = get_portmatch(pai, servname);
+ if (error)
+ SETERROR(error);
+
+ *pai = ai0;
+ }
+
+ ai0 = *pai;
+
+ /* NULL hostname, or numeric hostname */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
+ continue;
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
+ continue;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+ if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+ pai->ai_socktype = ex->e_socktype;
+ if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+ pai->ai_protocol = ex->e_protocol;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if (hostname == NULL) {
+ /*
+ * filter out AFs that are not supported by the kernel
+ * XXX errno?
+ */
+ if (!addrconfig(pai->ai_family))
+ continue;
+ error = explore_null(pai, servname, &cur->ai_next);
+ } else
+ error = explore_numeric_scope(pai, hostname, servname,
+ &cur->ai_next);
+
+ if (error)
+ goto free;
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ /*
+ * XXX
+ * If numreic representation of AF1 can be interpreted as FQDN
+ * representation of AF2, we need to think again about the code below.
+ */
+ if (sentinel.ai_next)
+ goto good;
+
+ if (pai->ai_flags & AI_NUMERICHOST)
+ SETERROR(EAI_NONAME);
+ if (hostname == NULL)
+ SETERROR(EAI_NONAME);
+
+ /*
+ * hostname as alphabetical name.
+ * We'll make sure that
+ * - if returning addrinfo list is empty, return non-zero error
+ * value (already known one or EAI_NONAME).
+ * - otherwise,
+ * + if we haven't had any errors, return 0 (i.e. success).
+ * + if we've had an error, free the list and return the error.
+ * without any assumption on the behavior of explore_fqdn().
+ */
+
+ /* first, try to query DNS for all possible address families. */
+ *pai = ai0;
+ error = explore_fqdn(pai, hostname, servname, &afai);
+ if (error) {
+ if (afai != NULL)
+ freeaddrinfo(afai);
+ goto free;
+ }
+ if (afai == NULL) {
+ error = EAI_NONAME; /*%< we've had no errors. */
+ goto free;
+ }
+
+ /*
+ * we would like to prefer AF_INET6 than AF_INET, so we'll make an
+ * outer loop by AFs.
+ */
+ for (ex = explore; ex->e_af >= 0; ex++) {
+ *pai = ai0;
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+
+ if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+ continue;
+ if (!MATCH(pai->ai_socktype, ex->e_socktype,
+ WILD_SOCKTYPE(ex))) {
+ continue;
+ }
+ if (!MATCH(pai->ai_protocol, ex->e_protocol,
+ WILD_PROTOCOL(ex))) {
+ continue;
+ }
+
+#ifdef AI_ADDRCONFIG
+ /*
+ * If AI_ADDRCONFIG is specified, check if we are
+ * expected to return the address family or not.
+ */
+ if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
+ !addrconfig(pai->ai_family))
+ continue;
+#endif
+
+ if (pai->ai_family == PF_UNSPEC)
+ pai->ai_family = ex->e_af;
+ if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+ pai->ai_socktype = ex->e_socktype;
+ if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+ pai->ai_protocol = ex->e_protocol;
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ continue;
+
+ if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) {
+ freeaddrinfo(afai);
+ goto free;
+ }
+
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+
+ freeaddrinfo(afai); /*%< afai must not be NULL at this point. */
+
+ if (sentinel.ai_next) {
+good:
+ *res = sentinel.ai_next;
+ return(SUCCESS);
+ } else {
+ /*
+ * All the process succeeded, but we've had an empty list.
+ * This can happen if the given hints do not match our
+ * candidates.
+ */
+ error = EAI_NONAME;
+ }
+
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ *res = NULL;
+ return(error);
+}
+
+/*%
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+ struct addrinfo *result;
+ struct addrinfo *cur;
+ struct net_data *net_data = init();
+ struct irs_ho *ho;
+ int error = 0;
+ char tmp[NS_MAXDNAME];
+ const char *cp;
+
+ INSIST(res != NULL && *res == NULL);
+
+ /*
+ * if the servname does not match socktype/protocol, ignore it.
+ */
+ if (get_portmatch(pai, servname) != 0)
+ return(0);
+
+ if (!net_data || !(ho = net_data->ho))
+ return(0);
+#if 0 /*%< XXX (notyet) */
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_addrtype == af) {
+ if (ns_samename(name, net_data->ho_last->h_name) == 1)
+ return (net_data->ho_last);
+ for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+ if (ns_samename(name, *hap) == 1)
+ return (net_data->ho_last);
+ }
+#endif
+ if (!strchr(hostname, '.') &&
+ (cp = res_hostalias(net_data->res, hostname,
+ tmp, sizeof(tmp))))
+ hostname = cp;
+ result = (*ho->addrinfo)(ho, hostname, pai);
+ if (!net_data->ho_stayopen) {
+ (*ho->minimize)(ho);
+ }
+ if (result == NULL) {
+ int e = h_errno;
+
+ switch(e) {
+ case NETDB_INTERNAL:
+ error = EAI_SYSTEM;
+ break;
+ case TRY_AGAIN:
+ error = EAI_AGAIN;
+ break;
+ case NO_RECOVERY:
+ error = EAI_FAIL;
+ break;
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ error = EAI_NONAME;
+ break;
+ default:
+ case NETDB_SUCCESS: /*%< should be impossible... */
+ error = EAI_NONAME;
+ break;
+ }
+ goto free;
+ }
+
+ for (cur = result; cur; cur = cur->ai_next) {
+ GET_PORT(cur, servname); /*%< XXX: redundant lookups... */
+ /* canonname should already be filled. */
+ }
+
+ *res = result;
+
+ return(0);
+
+free:
+ if (result)
+ freeaddrinfo(result);
+ return error;
+}
+
+static int
+explore_copy(pai, src0, res)
+ const struct addrinfo *pai; /*%< seed */
+ const struct addrinfo *src0; /*%< source */
+ struct addrinfo **res;
+{
+ int error;
+ struct addrinfo sentinel, *cur;
+ const struct addrinfo *src;
+
+ error = 0;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ for (src = src0; src != NULL; src = src->ai_next) {
+ if (src->ai_family != pai->ai_family)
+ continue;
+
+ cur->ai_next = copy_ai(src);
+ if (!cur->ai_next) {
+ error = EAI_MEMORY;
+ goto fail;
+ }
+
+ cur->ai_next->ai_socktype = pai->ai_socktype;
+ cur->ai_next->ai_protocol = pai->ai_protocol;
+ cur = cur->ai_next;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+fail:
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+static int
+explore_null(pai, servname, res)
+ const struct addrinfo *pai;
+ const char *servname;
+ struct addrinfo **res;
+{
+ const struct afd *afd;
+ struct addrinfo *cur;
+ struct addrinfo sentinel;
+ int error;
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (pai->ai_flags & AI_PASSIVE) {
+ GET_AI(cur->ai_next, afd, afd->a_addrany);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "anyaddr");
+ */
+ GET_PORT(cur->ai_next, servname);
+ } else {
+ GET_AI(cur->ai_next, afd, afd->a_loopback);
+ /* xxx meaningless?
+ * GET_CANONNAME(cur->ai_next, "localhost");
+ */
+ GET_PORT(cur->ai_next, servname);
+ }
+ cur = cur->ai_next;
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * numeric hostname
+ */
+static int
+explore_numeric(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+ const struct afd *afd;
+ struct addrinfo *cur;
+ struct addrinfo sentinel;
+ int error;
+ char pton[PTON_MAX];
+
+ *res = NULL;
+ sentinel.ai_next = NULL;
+ cur = &sentinel;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ switch (afd->a_af) {
+#if 0 /*X/Open spec*/
+ case AF_INET:
+ if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ SETERROR(EAI_FAMILY); /*xxx*/
+ }
+ break;
+#endif
+ default:
+ if (inet_pton(afd->a_af, hostname, pton) == 1) {
+ if (pai->ai_family == afd->a_af ||
+ pai->ai_family == PF_UNSPEC /*?*/) {
+ GET_AI(cur->ai_next, afd, pton);
+ GET_PORT(cur->ai_next, servname);
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ } else
+ SETERROR(EAI_FAMILY); /*xxx*/
+ }
+ break;
+ }
+
+ *res = sentinel.ai_next;
+ return 0;
+
+free:
+bad:
+ if (sentinel.ai_next)
+ freeaddrinfo(sentinel.ai_next);
+ return error;
+}
+
+/*%
+ * numeric hostname with scope
+ */
+static int
+explore_numeric_scope(pai, hostname, servname, res)
+ const struct addrinfo *pai;
+ const char *hostname;
+ const char *servname;
+ struct addrinfo **res;
+{
+#ifndef SCOPE_DELIMITER
+ return explore_numeric(pai, hostname, servname, res);
+#else
+ const struct afd *afd;
+ struct addrinfo *cur;
+ int error;
+ char *cp, *hostname2 = NULL, *scope, *addr;
+ struct sockaddr_in6 *sin6;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return 0;
+
+ if (!afd->a_scoped)
+ return explore_numeric(pai, hostname, servname, res);
+
+ cp = strchr(hostname, SCOPE_DELIMITER);
+ if (cp == NULL)
+ return explore_numeric(pai, hostname, servname, res);
+
+ /*
+ * Handle special case of <scoped_address><delimiter><scope id>
+ */
+ hostname2 = strdup(hostname);
+ if (hostname2 == NULL)
+ return EAI_MEMORY;
+ /* terminate at the delimiter */
+ hostname2[cp - hostname] = '\0';
+ addr = hostname2;
+ scope = cp + 1;
+
+ error = explore_numeric(pai, addr, servname, res);
+ if (error == 0) {
+ u_int32_t scopeid = 0;
+
+ for (cur = *res; cur; cur = cur->ai_next) {
+ if (cur->ai_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
+ if (!ip6_str2scopeid(scope, sin6, &scopeid)) {
+ free(hostname2);
+ return(EAI_NONAME); /*%< XXX: is return OK? */
+ }
+#ifdef HAVE_SIN6_SCOPE_ID
+ sin6->sin6_scope_id = scopeid;
+#endif
+ }
+ }
+
+ free(hostname2);
+
+ return error;
+#endif
+}
+
+static int
+get_canonname(pai, ai, str)
+ const struct addrinfo *pai;
+ struct addrinfo *ai;
+ const char *str;
+{
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+ if (ai->ai_canonname == NULL)
+ return EAI_MEMORY;
+ strcpy(ai->ai_canonname, str);
+ }
+ return 0;
+}
+
+static struct addrinfo *
+get_ai(pai, afd, addr)
+ const struct addrinfo *pai;
+ const struct afd *afd;
+ const char *addr;
+{
+ char *p;
+ struct addrinfo *ai;
+
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ + (afd->a_socklen));
+ if (ai == NULL)
+ return NULL;
+
+ memcpy(ai, pai, sizeof(struct addrinfo));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
+#ifdef HAVE_SA_LEN
+ ai->ai_addr->sa_len = afd->a_socklen;
+#endif
+ ai->ai_addrlen = afd->a_socklen;
+ ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+ p = (char *)(void *)(ai->ai_addr);
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+ return ai;
+}
+
+/* XXX need to malloc() the same way we do from other functions! */
+static struct addrinfo *
+copy_ai(pai)
+ const struct addrinfo *pai;
+{
+ struct addrinfo *ai;
+ size_t l;
+
+ l = sizeof(*ai) + pai->ai_addrlen;
+ if ((ai = (struct addrinfo *)malloc(l)) == NULL)
+ return NULL;
+ memset(ai, 0, l);
+ memcpy(ai, pai, sizeof(*ai));
+ ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+ memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
+
+ if (pai->ai_canonname) {
+ l = strlen(pai->ai_canonname) + 1;
+ if ((ai->ai_canonname = malloc(l)) == NULL) {
+ free(ai);
+ return NULL;
+ }
+ strcpy(ai->ai_canonname, pai->ai_canonname); /* (checked) */
+ } else {
+ /* just to make sure */
+ ai->ai_canonname = NULL;
+ }
+
+ ai->ai_next = NULL;
+
+ return ai;
+}
+
+static int
+get_portmatch(const struct addrinfo *ai, const char *servname) {
+
+ /* get_port does not touch first argument. when matchonly == 1. */
+ /* LINTED const cast */
+ return get_port((const struct addrinfo *)ai, servname, 1);
+}
+
+static int
+get_port(const struct addrinfo *ai, const char *servname, int matchonly) {
+ const char *proto;
+ struct servent *sp;
+ int port;
+ int allownumeric;
+
+ if (servname == NULL)
+ return 0;
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ return 0;
+ }
+
+ switch (ai->ai_socktype) {
+ case SOCK_RAW:
+ return EAI_SERVICE;
+ case SOCK_DGRAM:
+ case SOCK_STREAM:
+ allownumeric = 1;
+ break;
+ case ANY:
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ allownumeric = 1;
+ break;
+ default:
+ allownumeric = 0;
+ break;
+ }
+ break;
+ default:
+ return EAI_SOCKTYPE;
+ }
+
+ if (str_isnumber(servname)) {
+ if (!allownumeric)
+ return EAI_SERVICE;
+ port = atoi(servname);
+ if (port < 0 || port > 65535)
+ return EAI_SERVICE;
+ port = htons(port);
+ } else {
+ switch (ai->ai_socktype) {
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ default:
+ proto = NULL;
+ break;
+ }
+
+ if ((sp = getservbyname(servname, proto)) == NULL)
+ return EAI_SERVICE;
+ port = sp->s_port;
+ }
+
+ if (!matchonly) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)(void *)
+ ai->ai_addr)->sin_port = port;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)(void *)
+ ai->ai_addr)->sin6_port = port;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct afd *
+find_afd(af)
+ int af;
+{
+ const struct afd *afd;
+
+ if (af == PF_UNSPEC)
+ return NULL;
+ for (afd = afdl; afd->a_af; afd++) {
+ if (afd->a_af == af)
+ return afd;
+ }
+ return NULL;
+}
+
+/*%
+ * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
+ * if the code is right or not.
+ */
+static int
+addrconfig(af)
+ int af;
+{
+ int s;
+
+ /* XXX errno */
+ s = socket(af, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EMFILE)
+ return 0;
+ } else
+ close(s);
+ return 1;
+}
+
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6,
+ u_int32_t *scopeidp)
+{
+ u_int32_t scopeid;
+ u_long lscopeid;
+ struct in6_addr *a6 = &sin6->sin6_addr;
+ char *ep;
+
+ /* empty scopeid portion is invalid */
+ if (*scope == '\0')
+ return (0);
+
+#ifdef USE_IFNAMELINKID
+ if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(a6)) {
+ /*
+ * Using interface names as link indices can be allowed
+ * only when we can assume a one-to-one mappings between
+ * links and interfaces. See comments in getnameinfo.c.
+ */
+ scopeid = if_nametoindex(scope);
+ if (scopeid == 0)
+ goto trynumeric;
+ *scopeidp = scopeid;
+ return (1);
+ }
+#endif
+
+ /* still unclear about literal, allow numeric only - placeholder */
+ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+ goto trynumeric;
+ if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+ goto trynumeric;
+ else
+ goto trynumeric; /*%< global */
+ /* try to convert to a numeric id as a last resort */
+trynumeric:
+ errno = 0;
+ lscopeid = strtoul(scope, &ep, 10);
+ scopeid = lscopeid & 0xffffffff;
+ if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) {
+ *scopeidp = scopeid;
+ return (1);
+ } else
+ return (0);
+}
+
+struct addrinfo *
+hostent2addrinfo(hp, pai)
+ struct hostent *hp;
+ const struct addrinfo *pai;
+{
+ int i, af, error = 0;
+ char **aplist = NULL, *ap;
+ struct addrinfo sentinel, *cur;
+ const struct afd *afd;
+
+ af = hp->h_addrtype;
+ if (pai->ai_family != AF_UNSPEC && af != pai->ai_family)
+ return(NULL);
+
+ afd = find_afd(af);
+ if (afd == NULL)
+ return(NULL);
+
+ aplist = hp->h_addr_list;
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ for (i = 0; (ap = aplist[i]) != NULL; i++) {
+#if 0 /*%< the trick seems too much */
+ af = hp->h_addr_list;
+ if (af == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+ af = AF_INET;
+ ap = ap + sizeof(struct in6_addr)
+ - sizeof(struct in_addr);
+ }
+ afd = find_afd(af);
+ if (afd == NULL)
+ continue;
+#endif /* 0 */
+
+ GET_AI(cur->ai_next, afd, ap);
+
+ /* GET_PORT(cur->ai_next, servname); */
+ if ((pai->ai_flags & AI_CANONNAME) != 0) {
+ /*
+ * RFC2553 says that ai_canonname will be set only for
+ * the first element. we do it for all the elements,
+ * just for convenience.
+ */
+ GET_CANONNAME(cur->ai_next, hp->h_name);
+ }
+ while (cur->ai_next) /*%< no need to loop, actually. */
+ cur = cur->ai_next;
+ continue;
+
+ free:
+ if (cur->ai_next)
+ freeaddrinfo(cur->ai_next);
+ cur->ai_next = NULL;
+ /* continue, without tht pointer CUR advanced. */
+ }
+
+ return(sentinel.ai_next);
+}
+
+struct addrinfo *
+addr2addrinfo(pai, cp)
+ const struct addrinfo *pai;
+ const char *cp;
+{
+ const struct afd *afd;
+
+ afd = find_afd(pai->ai_family);
+ if (afd == NULL)
+ return(NULL);
+
+ return(get_ai(pai, afd, cp));
+}
+
+static struct net_data *
+init()
+{
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->ho) {
+ net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+ if (!net_data->ho || !net_data->res) {
+error:
+ errno = EIO;
+ if (net_data && net_data->res)
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gethostent.c b/usr/src/lib/libresolv2_joy/common/irs/gethostent.c
new file mode 100644
index 0000000000..c4751c2c80
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gethostent.c
@@ -0,0 +1,1096 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gethostent.c,v 1.8 2006/01/10 05:06:00 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+ char * aliases[1];
+ char * addrs[2];
+ char addr[NS_IN6ADDRSZ];
+ char name[NS_MAXDNAME + 1];
+ struct hostent host;
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static void freepvt(struct net_data *);
+static struct hostent *fakeaddr(const char *, int, struct net_data *);
+
+#ifdef SUNW_OVERRIDE_RETRY
+extern int __res_retry(int);
+extern int __res_retry_reset(void);
+#endif /* SUNW_OVERRIDE_RETRY */
+
+
+/* Public */
+
+struct hostent *
+gethostbyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (gethostbyname_p(name, net_data));
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af) {
+ struct net_data *net_data = init();
+
+ return (gethostbyname2_p(name, af, net_data));
+}
+
+struct hostent *
+gethostbyaddr(const char *addr, int len, int af) {
+ struct net_data *net_data = init();
+
+ return (gethostbyaddr_p(addr, len, af, net_data));
+}
+
+struct hostent *
+gethostent() {
+ struct net_data *net_data = init();
+
+ return (gethostent_p(net_data));
+}
+
+void
+sethostent(int stayopen) {
+ struct net_data *net_data = init();
+ sethostent_p(stayopen, net_data);
+}
+
+
+void
+endhostent() {
+ struct net_data *net_data = init();
+ endhostent_p(net_data);
+}
+
+/* Shared private. */
+
+struct hostent *
+gethostbyname_p(const char *name, struct net_data *net_data) {
+ struct hostent *hp;
+
+ if (!net_data)
+ return (NULL);
+
+ if (net_data->res->options & RES_USE_INET6) {
+ hp = gethostbyname2_p(name, AF_INET6, net_data);
+ if (hp)
+ return (hp);
+ }
+ return (gethostbyname2_p(name, AF_INET, net_data));
+}
+
+struct hostent *
+gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
+ struct irs_ho *ho;
+ char tmp[NS_MAXDNAME];
+ struct hostent *hp;
+ const char *cp;
+ char **hap;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_addrtype == af) {
+ if (ns_samename(name, net_data->ho_last->h_name) == 1)
+ return (net_data->ho_last);
+ for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+ if (ns_samename(name, *hap) == 1)
+ return (net_data->ho_last);
+ }
+ if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
+ tmp, sizeof tmp)))
+ name = cp;
+ if ((hp = fakeaddr(name, af, net_data)) != NULL)
+ return (hp);
+#ifdef SUNW_OVERRIDE_RETRY
+ net_data->res->retry = __res_retry(net_data->res->retry);
+#endif /* SUNW_OVERRIDE_RETRY */
+ net_data->ho_last = (*ho->byname2)(ho, name, af);
+#ifdef SUNW_OVERRIDE_RETRY
+ net_data->res->retry = __res_retry_reset();
+#endif /* SUNW_OVERRIDE_RETRY */
+ if (!net_data->ho_stayopen)
+ endhostent();
+ return (net_data->ho_last);
+}
+
+struct hostent *
+gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
+ struct irs_ho *ho;
+ char **hap;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ if (net_data->ho_stayopen && net_data->ho_last &&
+ net_data->ho_last->h_length == len)
+ for (hap = net_data->ho_last->h_addr_list;
+ hap && *hap;
+ hap++)
+ if (!memcmp(addr, *hap, len))
+ return (net_data->ho_last);
+ net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
+ if (!net_data->ho_stayopen)
+ endhostent();
+ return (net_data->ho_last);
+}
+
+
+struct hostent *
+gethostent_p(struct net_data *net_data) {
+ struct irs_ho *ho;
+ struct hostent *hp;
+
+ if (!net_data || !(ho = net_data->ho))
+ return (NULL);
+ while ((hp = (*ho->next)(ho)) != NULL &&
+ hp->h_addrtype == AF_INET6 &&
+ (net_data->res->options & RES_USE_INET6) == 0U)
+ continue;
+ net_data->ho_last = hp;
+ return (net_data->ho_last);
+}
+
+
+void
+sethostent_p(int stayopen, struct net_data *net_data) {
+ struct irs_ho *ho;
+
+ if (!net_data || !(ho = net_data->ho))
+ return;
+ freepvt(net_data);
+ (*ho->rewind)(ho);
+ net_data->ho_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endhostent_p(struct net_data *net_data) {
+ struct irs_ho *ho;
+
+ if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
+ (*ho->minimize)(ho);
+}
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+static const unsigned char in6addr_compat[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
+ ((x)->s6_addr[12] != 0 || \
+ (x)->s6_addr[13] != 0 || \
+ (x)->s6_addr[14] != 0 || \
+ ((x)->s6_addr[15] != 0 && \
+ (x)->s6_addr[15] != 1)))
+#endif
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
+#endif
+
+static const unsigned char in6addr_mapped[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
+
+static int scan_interfaces(int *, int *);
+static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
+
+/*%
+ * Public functions
+ */
+
+/*%
+ * AI_V4MAPPED + AF_INET6
+ * If no IPv6 address then a query for IPv4 and map returned values.
+ *
+ * AI_ALL + AI_V4MAPPED + AF_INET6
+ * Return IPv6 and IPv4 mapped.
+ *
+ * AI_ADDRCONFIG
+ * Only return IPv6 / IPv4 address if there is an interface of that
+ * type active.
+ */
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *error_num) {
+ int have_v4 = 1, have_v6 = 1;
+ struct in_addr in4;
+ struct in6_addr in6;
+ struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
+ int v4 = 0, v6 = 0;
+ struct net_data *net_data = init();
+ u_long options;
+ int tmp_err;
+
+ if (net_data == NULL) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /* If we care about active interfaces then check. */
+ if ((flags & AI_ADDRCONFIG) != 0)
+ if (scan_interfaces(&have_v4, &have_v6) == -1) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /* Check for literal address. */
+ if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
+ v6 = inet_pton(AF_INET6, name, &in6);
+
+ /* Impossible combination? */
+
+ if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
+ (af == AF_INET && v6 == 1) ||
+ (have_v4 == 0 && v4 == 1) ||
+ (have_v6 == 0 && v6 == 1) ||
+ (have_v4 == 0 && af == AF_INET) ||
+ (have_v6 == 0 && af == AF_INET6)) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ /* Literal address? */
+ if (v4 == 1 || v6 == 1) {
+ char *addr_list[2];
+ char *aliases[1];
+
+ DE_CONST(name, he.h_name);
+ he.h_addr_list = addr_list;
+ he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
+ he.h_addr_list[1] = NULL;
+ he.h_aliases = aliases;
+ he.h_aliases[0] = NULL;
+ he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
+ he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
+ return (copyandmerge(&he, NULL, af, error_num));
+ }
+
+ options = net_data->res->options;
+ net_data->res->options &= ~RES_USE_INET6;
+
+ tmp_err = NO_RECOVERY;
+ if (have_v6 && af == AF_INET6) {
+ he2 = gethostbyname2_p(name, AF_INET6, net_data);
+ if (he2 != NULL) {
+ he1 = copyandmerge(he2, NULL, af, error_num);
+ if (he1 == NULL)
+ return (NULL);
+ he2 = NULL;
+ } else {
+ tmp_err = net_data->res->res_h_errno;
+ }
+ }
+
+ if (have_v4 &&
+ ((af == AF_INET) ||
+ (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
+ (he1 == NULL || (flags & AI_ALL) != 0)))) {
+ he2 = gethostbyname2_p(name, AF_INET, net_data);
+ if (he1 == NULL && he2 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ } else
+ *error_num = tmp_err;
+
+ net_data->res->options = options;
+
+ he3 = copyandmerge(he1, he2, af, error_num);
+
+ if (he1 != NULL)
+ freehostent(he1);
+ return (he3);
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
+ struct hostent *he1, *he2;
+ struct net_data *net_data = init();
+
+ /* Sanity Checks. */
+#ifdef ORIGINAL_ISC_CODE
+ if (src == NULL) {
+#else
+ /* this change was added circa May 2009, but not in ISC libbind 6.0 */
+ if (src == NULL|| net_data == NULL) {
+#endif /* ORIGINAL_ISC_CODE */
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ switch (af) {
+ case AF_INET:
+ if (len != (size_t)INADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ case AF_INET6:
+ if (len != (size_t)IN6ADDRSZ) {
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+ break;
+ default:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+ }
+
+ /*
+ * Lookup IPv4 and IPv4 mapped/compatible addresses
+ */
+ if ((af == AF_INET6 &&
+ IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
+ (af == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
+ (af == AF_INET)) {
+ const char *cp = src;
+
+ if (af == AF_INET6)
+ cp += 12;
+ he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
+ if (he1 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ he2 = copyandmerge(he1, NULL, af, error_num);
+ if (he2 == NULL)
+ return (NULL);
+ /*
+ * Restore original address if mapped/compatible.
+ */
+ if (af == AF_INET6)
+ memcpy(he1->h_addr, src, len);
+ return (he2);
+ }
+
+ /*
+ * Lookup IPv6 address.
+ */
+ if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
+ *error_num = HOST_NOT_FOUND;
+ return (NULL);
+ }
+
+ he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
+ if (he1 == NULL) {
+ *error_num = net_data->res->res_h_errno;
+ return (NULL);
+ }
+ return (copyandmerge(he1, NULL, af, error_num));
+}
+
+void
+freehostent(struct hostent *he) {
+ char **cpp;
+ int names = 1;
+ int addresses = 1;
+
+ memput(he->h_name, strlen(he->h_name) + 1);
+
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ memput(*cpp, (he->h_addrtype == AF_INET) ?
+ INADDRSZ : IN6ADDRSZ);
+ *cpp = NULL;
+ cpp++;
+ addresses++;
+ }
+
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ memput(*cpp, strlen(*cpp) + 1);
+ cpp++;
+ names++;
+ }
+
+ memput(he->h_aliases, sizeof(char *) * (names));
+ memput(he->h_addr_list, sizeof(char *) * (addresses));
+ memput(he, sizeof *he);
+}
+
+/*%
+ * Private
+ */
+
+/*%
+ * Scan the interface table and set have_v4 and have_v6 depending
+ * upon whether there are IPv4 and IPv6 interface addresses.
+ *
+ * Returns:
+ * 0 on success
+ * -1 on failure.
+ */
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
+ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
+
+#ifdef __hpux
+#define lifc_len iflc_len
+#define lifc_buf iflc_buf
+#define lifc_req iflc_req
+#define LIFCONF if_laddrconf
+#else
+#define SETFAMILYFLAGS
+#define LIFCONF lifconf
+#endif
+
+#ifdef __hpux
+#define lifr_addr iflr_addr
+#define lifr_name iflr_name
+#define lifr_dstaddr iflr_dstaddr
+#define lifr_flags iflr_flags
+#define ss_family sa_family
+#define LIFREQ if_laddrreq
+#else
+#define LIFREQ lifreq
+#endif
+
+static void
+scan_interfaces6(int *have_v4, int *have_v6) {
+ struct LIFCONF lifc;
+ struct LIFREQ lifreq;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *buf = NULL, *cp, *cplim;
+ static unsigned int bufsiz = 4095;
+ int s, cpsize, n;
+
+ /* Get interface list from system. */
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
+ goto cleanup;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = memget(bufsiz);
+ if (buf == NULL)
+ goto cleanup;
+#ifdef SETFAMILYFLAGS
+ lifc.lifc_family = AF_UNSPEC; /*%< request all families */
+ lifc.lifc_flags = 0;
+#endif
+ lifc.lifc_len = bufsiz;
+ lifc.lifc_buf = buf;
+ if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * lifc.lifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
+ break;
+ }
+ if ((n == -1) && errno != EINVAL)
+ goto cleanup;
+
+ if (bufsiz > 1000000)
+ goto cleanup;
+
+ memput(buf, bufsiz);
+ bufsiz += 4096;
+ }
+
+ /* Parse system's interface list. */
+ cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */
+ for (cp = buf;
+ (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+ cp += cpsize) {
+ memcpy(&lifreq, cp, sizeof lifreq);
+#ifdef HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+ if (lifreq.lifr_addr.sa_len == 0)
+ lifreq.lifr_addr.sa_len = 16;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+ cpsize = sizeof lifreq;
+ if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
+ cpsize += (int)lifreq.lifr_addr.sa_len -
+ (int)(sizeof (struct sockaddr));
+#else
+ cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof lifreq;
+#else
+ cpsize = sizeof lifreq.lifr_name;
+ /* XXX maybe this should be a hard error? */
+ if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
+ continue;
+#endif
+ switch (lifreq.lifr_addr.ss_family) {
+ case AF_INET:
+ if (*have_v4 == 0) {
+ memcpy(&in4,
+ &((struct sockaddr_in *)
+ &lifreq.lifr_addr)->sin_addr,
+ sizeof in4);
+ if (in4.s_addr == INADDR_ANY)
+ break;
+ n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+ if (n < 0)
+ break;
+ if ((lifreq.lifr_flags & IFF_UP) == 0)
+ break;
+ *have_v4 = 1;
+ }
+ break;
+ case AF_INET6:
+ if (*have_v6 == 0) {
+ memcpy(&in6,
+ &((struct sockaddr_in6 *)
+ &lifreq.lifr_addr)->sin6_addr, sizeof in6);
+ if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
+ break;
+ n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+ if (n < 0)
+ break;
+ if ((lifreq.lifr_flags & IFF_UP) == 0)
+ break;
+ *have_v6 = 1;
+ }
+ break;
+ }
+ }
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return;
+ cleanup:
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ if (s != -1)
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return;
+}
+#endif
+
+#if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+static void
+scan_linux6(int *have_v6) {
+ FILE *proc = NULL;
+ char address[33];
+ char name[IF_NAMESIZE+1];
+ int ifindex, prefix, flag3, flag4;
+
+ proc = fopen("/proc/net/if_inet6", "r");
+ if (proc == NULL)
+ return;
+
+ if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n",
+ address, &ifindex, &prefix, &flag3, &flag4, name) == 6)
+ *have_v6 = 1;
+ fclose(proc);
+ return;
+}
+#endif
+
+static int
+scan_interfaces(int *have_v4, int *have_v6) {
+ struct ifconf ifc;
+ union {
+ char _pad[256]; /*%< leave space for IPv6 addresses */
+ struct ifreq ifreq;
+ } u;
+ struct in_addr in4;
+ struct in6_addr in6;
+ char *buf = NULL, *cp, *cplim;
+ static unsigned int bufsiz = 4095;
+ int s, n;
+ size_t cpsize;
+
+ /* Set to zero. Used as loop terminators below. */
+ *have_v4 = *have_v6 = 0;
+
+#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
+ !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
+ /*
+ * Try to scan the interfaces using IPv6 ioctls().
+ */
+ scan_interfaces6(have_v4, have_v6);
+ if (*have_v4 != 0 && *have_v6 != 0)
+ return (0);
+#endif
+#ifdef __linux
+ scan_linux6(have_v6);
+#endif
+
+ /* Get interface list from system. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ goto err_ret;
+
+ /*
+ * Grow buffer until large enough to contain all interface
+ * descriptions.
+ */
+ for (;;) {
+ buf = memget(bufsiz);
+ if (buf == NULL)
+ goto err_ret;
+ ifc.ifc_len = bufsiz;
+ ifc.ifc_buf = buf;
+#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
+ /*
+ * This is a fix for IRIX OS in which the call to ioctl with
+ * the flag SIOCGIFCONF may not return an entry for all the
+ * interfaces like most flavors of Unix.
+ */
+ if (emul_ioctl(&ifc) >= 0)
+ break;
+#else
+ if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
+ /*
+ * Some OS's just return what will fit rather
+ * than set EINVAL if the buffer is too small
+ * to fit all the interfaces in. If
+ * ifc.ifc_len is too near to the end of the
+ * buffer we will grow it just in case and
+ * retry.
+ */
+ if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
+ break;
+ }
+#endif
+ if ((n == -1) && errno != EINVAL)
+ goto err_ret;
+
+ if (bufsiz > 1000000)
+ goto err_ret;
+
+ memput(buf, bufsiz);
+ bufsiz += 4096;
+ }
+
+ /* Parse system's interface list. */
+ cplim = buf + ifc.ifc_len; /*%< skip over if's with big ifr_addr's */
+ for (cp = buf;
+ (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+ cp += cpsize) {
+ memcpy(&u.ifreq, cp, sizeof u.ifreq);
+#ifdef HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+ if (u.ifreq.ifr_addr.sa_len == 0)
+ u.ifreq.ifr_addr.sa_len = 16;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+ cpsize = sizeof u.ifreq;
+ if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
+ cpsize += (int)u.ifreq.ifr_addr.sa_len -
+ (int)(sizeof (struct sockaddr));
+#else
+ cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+ if (cpsize > sizeof u.ifreq && cpsize <= sizeof u)
+ memcpy(&u.ifreq, cp, cpsize);
+#elif defined SIOCGIFCONF_ADDR
+ cpsize = sizeof u.ifreq;
+#else
+ cpsize = sizeof u.ifreq.ifr_name;
+ /* XXX maybe this should be a hard error? */
+ if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
+ continue;
+#endif
+ switch (u.ifreq.ifr_addr.sa_family) {
+ case AF_INET:
+ if (*have_v4 == 0) {
+ memcpy(&in4,
+ &((struct sockaddr_in *)
+ &u.ifreq.ifr_addr)->sin_addr,
+ sizeof in4);
+ if (in4.s_addr == INADDR_ANY)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
+ if (n < 0)
+ break;
+ if ((u.ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v4 = 1;
+ }
+ break;
+ case AF_INET6:
+ if (*have_v6 == 0) {
+ memcpy(&in6,
+ &((struct sockaddr_in6 *)
+ &u.ifreq.ifr_addr)->sin6_addr,
+ sizeof in6);
+ if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
+ break;
+ n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
+ if (n < 0)
+ break;
+ if ((u.ifreq.ifr_flags & IFF_UP) == 0)
+ break;
+ *have_v6 = 1;
+ }
+ break;
+ }
+ }
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return (0);
+ err_ret:
+ if (buf != NULL)
+ memput(buf, bufsiz);
+ if (s != -1)
+ close(s);
+ /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+ return (-1);
+}
+
+static struct hostent *
+copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
+ struct hostent *he = NULL;
+ int addresses = 1; /*%< NULL terminator */
+ int names = 1; /*%< NULL terminator */
+ int len = 0;
+ char **cpp, **npp;
+
+ /*
+ * Work out array sizes;
+ */
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ cpp = he1->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ addresses++;
+ cpp++;
+ }
+ if (he1 == NULL) {
+ cpp = he2->h_aliases;
+ while (*cpp != NULL) {
+ names++;
+ cpp++;
+ }
+ }
+ }
+
+ if (addresses == 1) {
+ *error_num = NO_ADDRESS;
+ return (NULL);
+ }
+
+ he = memget(sizeof *he);
+ if (he == NULL)
+ goto no_recovery;
+
+ he->h_addr_list = memget(sizeof(char *) * (addresses));
+ if (he->h_addr_list == NULL)
+ goto cleanup0;
+ memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
+
+ /* copy addresses */
+ npp = he->h_addr_list;
+ if (he1 != NULL) {
+ cpp = he1->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /* convert to mapped if required */
+ if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ if (he2 != NULL) {
+ cpp = he2->h_addr_list;
+ while (*cpp != NULL) {
+ *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ if (*npp == NULL)
+ goto cleanup1;
+ /* convert to mapped if required */
+ if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
+ memcpy(*npp, in6addr_mapped,
+ sizeof in6addr_mapped);
+ memcpy(*npp + sizeof in6addr_mapped, *cpp,
+ INADDRSZ);
+ } else {
+ memcpy(*npp, *cpp,
+ (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ }
+ cpp++;
+ npp++;
+ }
+ }
+
+ he->h_aliases = memget(sizeof(char *) * (names));
+ if (he->h_aliases == NULL)
+ goto cleanup1;
+ memset(he->h_aliases, 0, sizeof(char *) * (names));
+
+ /* copy aliases */
+ npp = he->h_aliases;
+ cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
+ while (*cpp != NULL) {
+ len = strlen (*cpp) + 1;
+ *npp = memget(len);
+ if (*npp == NULL)
+ goto cleanup2;
+ strcpy(*npp, *cpp);
+ npp++;
+ cpp++;
+ }
+
+ /* copy hostname */
+ he->h_name = memget(strlen((he1 != NULL) ?
+ he1->h_name : he2->h_name) + 1);
+ if (he->h_name == NULL)
+ goto cleanup2;
+ strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
+
+ /* set address type and length */
+ he->h_addrtype = af;
+ he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
+ return(he);
+
+ cleanup2:
+ cpp = he->h_aliases;
+ while (*cpp != NULL) {
+ memput(*cpp, strlen(*cpp) + 1);
+ cpp++;
+ }
+ memput(he->h_aliases, sizeof(char *) * (names));
+
+ cleanup1:
+ cpp = he->h_addr_list;
+ while (*cpp != NULL) {
+ memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+ *cpp = NULL;
+ cpp++;
+ }
+ memput(he->h_addr_list, sizeof(char *) * (addresses));
+
+ cleanup0:
+ memput(he, sizeof *he);
+
+ no_recovery:
+ *error_num = NO_RECOVERY;
+ return (NULL);
+}
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->ho) {
+ net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+ if (!net_data->ho || !net_data->res) {
+ error:
+ errno = EIO;
+
+#ifdef SUNW_SETHERRNO
+ h_errno = NETDB_INTERNAL;
+#endif /* SUNW_SETHERRNO */
+ if (net_data && net_data->res)
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+ if (net_data->ho_data) {
+ free(net_data->ho_data);
+ net_data->ho_data = NULL;
+ }
+}
+
+static struct hostent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+ struct pvt *pvt;
+
+ freepvt(net_data);
+ net_data->ho_data = malloc(sizeof (struct pvt));
+ if (!net_data->ho_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->ho_data;
+#ifndef __bsdi__
+ /*
+ * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
+ * in its interpretation of its input, and it will only return "1" if
+ * the input string is a formally valid(and thus unambiguous with
+ * respect to host names) internet address specification for this AF.
+ *
+ * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
+ */
+ if (inet_pton(af, name, pvt->addr) != 1) {
+#else
+ /* BSDI XXX
+ * We put this back to inet_aton -- we really want the old behavior
+ * Long live 127.1...
+ */
+ if ((af != AF_INET ||
+ inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
+ inet_pton(af, name, pvt->addr) != 1) {
+#endif
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ strncpy(pvt->name, name, NS_MAXDNAME);
+ pvt->name[NS_MAXDNAME] = '\0';
+ if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) {
+ map_v4v6_address(pvt->addr, pvt->addr);
+ af = AF_INET6;
+ }
+ pvt->host.h_addrtype = af;
+ switch(af) {
+ case AF_INET:
+ pvt->host.h_length = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ pvt->host.h_length = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt->host.h_name = pvt->name;
+ pvt->host.h_aliases = pvt->aliases;
+ pvt->aliases[0] = NULL;
+ pvt->addrs[0] = (char *)pvt->addr;
+ pvt->addrs[1] = NULL;
+ pvt->host.h_addr_list = pvt->addrs;
+ RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
+ return (&pvt->host);
+}
+
+#ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */
+ struct hostent *rhp;
+ char **haddr;
+ u_long old_options;
+ char hname2[MAXDNAME+1];
+
+ if (af == AF_INET) {
+ /*
+ * turn off search as the name should be absolute,
+ * 'localhost' should be matched by defnames
+ */
+ strncpy(hname2, hp->h_name, MAXDNAME);
+ hname2[MAXDNAME] = '\0';
+ old_options = net_data->res->options;
+ net_data->res->options &= ~RES_DNSRCH;
+ net_data->res->options |= RES_DEFNAMES;
+ if (!(rhp = gethostbyname(hname2))) {
+ net_data->res->options = old_options;
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ net_data->res->options = old_options;
+ for (haddr = rhp->h_addr_list; *haddr; haddr++)
+ if (!memcmp(*haddr, addr, INADDRSZ))
+ break;
+ if (!*haddr) {
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ }
+#endif /* grot */
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/gethostent_r.c b/usr/src/lib/libresolv2_joy/common/irs/gethostent_r.c
new file mode 100644
index 0000000000..1971677c5d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/gethostent_r.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: gethostent_r.c,v 1.9 2005/09/03 12:41:37 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int gethostent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#pragma redefine extname res_gethostbyname joy_res_gethostbyname
+#pragma redefine extname res_gethostbyaddr joy_res_gethostbyaddr
+
+#ifdef HOST_R_RETURN
+
+static HOST_R_RETURN
+copy_hostent(struct hostent *, struct hostent *, HOST_R_COPY_ARGS);
+
+HOST_R_RETURN
+gethostbyname_r(const char *name, struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostbyname(name);
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+HOST_R_RETURN
+gethostbyaddr_r(const char *addr, int len, int type,
+ struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostbyaddr(addr, len, type);
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+HOST_R_RETURN
+gethostent_r(struct hostent *hptr, HOST_R_ARGS) {
+ struct hostent *he = gethostent();
+#ifdef HOST_R_SETANSWER
+ int n = 0;
+#endif
+
+#ifdef HOST_R_ERRNO
+ HOST_R_ERRNO;
+#endif
+
+#ifdef HOST_R_SETANSWER
+ if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = hptr;
+
+ return (n);
+#else
+ if (he == NULL)
+ return (HOST_R_BAD);
+
+ return (copy_hostent(he, hptr, HOST_R_COPY));
+#endif
+}
+
+HOST_R_SET_RETURN
+#ifdef HOST_R_ENT_ARGS
+sethostent_r(int stay_open, HOST_R_ENT_ARGS)
+#else
+sethostent_r(int stay_open)
+#endif
+{
+#ifdef HOST_R_ENT_ARGS
+ UNUSED(hdptr);
+#endif
+ sethostent(stay_open);
+#ifdef HOST_R_SET_RESULT
+ return (HOST_R_SET_RESULT);
+#endif
+}
+
+HOST_R_END_RETURN
+#ifdef HOST_R_ENT_ARGS
+endhostent_r(HOST_R_ENT_ARGS)
+#else
+endhostent_r(void)
+#endif
+{
+#ifdef HOST_R_ENT_ARGS
+ UNUSED(hdptr);
+#endif
+ endhostent();
+ HOST_R_END_RESULT(HOST_R_OK);
+}
+
+/* Private */
+
+#ifndef HOSTENT_DATA
+static HOST_R_RETURN
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+ char *cp;
+ char **ptr;
+ int i, n;
+ int nptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ nptr = 2; /*%< NULL ptrs */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+ len += he->h_length;
+ }
+ for (i = 0; he->h_aliases[i]; i++, nptr++) {
+ len += strlen(he->h_aliases[i]) + 1;
+ }
+ len += strlen(he->h_name) + 1;
+ len += nptr * sizeof(char*);
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (HOST_R_BAD);
+ }
+
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)ALIGN(buf);
+ cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
+
+ /* copy address list */
+ hptr->h_addr_list = ptr;
+ for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ }
+ hptr->h_addr_list[i] = NULL;
+ ptr++;
+
+ /* copy official name */
+ n = strlen(he->h_name) + 1;
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ hptr->h_aliases = ptr;
+ for (i = 0 ; he->h_aliases[i]; i++) {
+ n = strlen(he->h_aliases[i]) + 1;
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (HOST_R_OK);
+}
+#else /* !HOSTENT_DATA */
+static int
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ /* copy up to first 35 addresses */
+ i = 0;
+ cp = hdptr->hostbuf;
+ eob = hdptr->hostbuf + sizeof(hdptr->hostbuf);
+ hptr->h_addr_list = hdptr->h_addr_ptrs;
+ while (he->h_addr_list[i] && i < (_MAXADDRS)) {
+ if (n < (eob - cp)) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ hptr->h_addr_list[i] = NULL;
+
+ /* copy official name */
+ if ((n = strlen(he->h_name) + 1) < (eob - cp)) {
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ hptr->h_aliases = hdptr->host_aliases;
+ while (he->h_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(he->h_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (HOST_R_OK);
+}
+#endif /* !HOSTENT_DATA */
+#else /* HOST_R_RETURN */
+ static int gethostent_r_unknown_system = 0;
+#endif /* HOST_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getnameinfo.c b/usr/src/lib/libresolv2_joy/common/irs/getnameinfo.c
new file mode 100644
index 0000000000..360bda8bfe
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getnameinfo.c
@@ -0,0 +1,334 @@
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ */
+
+#if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
+#ifndef IF_NAMESIZE
+# ifdef IFNAMSIZ
+# define IF_NAMESIZE IFNAMSIZ
+# else
+# define IF_NAMESIZE 16
+# endif
+#endif
+#endif
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by WIDE Project and
+ * its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+ */
+
+#include <port_before.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <port_after.h>
+
+/*%
+ * Note that a_off will be dynamically adjusted so that to be consistent
+ * with the definition of sockaddr_in{,6}.
+ * The value presented below is just a guess.
+ */
+static struct afd {
+ int a_af;
+ int a_addrlen;
+ size_t a_socklen;
+ int a_off;
+} afdl [] = {
+ /* first entry is linked last... */
+ {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+ offsetof(struct sockaddr_in, sin_addr)},
+ {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+ offsetof(struct sockaddr_in6, sin6_addr)},
+ {0, 0, 0, 0},
+};
+
+struct sockinet {
+#ifdef HAVE_SA_LEN
+ u_char si_len;
+#endif
+ u_char si_family;
+ u_short si_port;
+};
+
+static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
+ size_t, int));
+#ifdef HAVE_SIN6_SCOPE_ID
+static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int));
+#endif
+
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+ const struct sockaddr *sa;
+ size_t salen;
+ char *host;
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int flags;
+{
+ struct afd *afd;
+ struct servent *sp;
+ struct hostent *hp;
+ u_short port;
+#ifdef HAVE_SA_LEN
+ size_t len;
+#endif
+ int family, i;
+ const char *addr;
+ char *p;
+ char numserv[512];
+ char numaddr[512];
+ const struct sockaddr_in6 *sin6;
+
+ if (sa == NULL)
+ return EAI_FAIL;
+
+#ifdef HAVE_SA_LEN
+ len = sa->sa_len;
+ if (len != salen) return EAI_FAIL;
+#endif
+
+ family = sa->sa_family;
+ for (i = 0; afdl[i].a_af; i++)
+ if (afdl[i].a_af == family) {
+ afd = &afdl[i];
+ goto found;
+ }
+ return EAI_FAMILY;
+
+ found:
+ if (salen != afd->a_socklen) return EAI_FAIL;
+
+ port = ((const struct sockinet *)sa)->si_port; /*%< network byte order */
+ addr = (const char *)sa + afd->a_off;
+
+ if (serv == NULL || servlen == 0U) {
+ /*
+ * rfc2553bis says that serv == NULL or servlen == 0 means that
+ * the caller does not want the result.
+ */
+ } else if (flags & NI_NUMERICSERV) {
+ sprintf(numserv, "%d", ntohs(port));
+ if (strlen(numserv) > servlen)
+ return EAI_MEMORY;
+ strcpy(serv, numserv);
+ } else {
+ sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
+ if (sp) {
+ if (strlen(sp->s_name) + 1 > servlen)
+ return EAI_MEMORY;
+ strcpy(serv, sp->s_name);
+ } else
+ return EAI_NONAME;
+ }
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (ntohl(*(const u_int32_t *)addr) >> IN_CLASSA_NSHIFT == 0)
+ flags |= NI_NUMERICHOST;
+ break;
+ case AF_INET6:
+ sin6 = (const struct sockaddr_in6 *)sa;
+ switch (sin6->sin6_addr.s6_addr[0]) {
+ case 0x00:
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ ;
+ else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+ ;
+ else
+ flags |= NI_NUMERICHOST;
+ break;
+ default:
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ flags |= NI_NUMERICHOST;
+ else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ flags |= NI_NUMERICHOST;
+ break;
+ }
+ break;
+ }
+ if (host == NULL || hostlen == 0U) {
+ /*
+ * rfc2553bis says that host == NULL or hostlen == 0 means that
+ * the caller does not want the result.
+ */
+ } else if (flags & NI_NUMERICHOST) {
+ goto numeric;
+ } else {
+ hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+
+ if (hp) {
+ if (flags & NI_NOFQDN) {
+ p = strchr(hp->h_name, '.');
+ if (p) *p = '\0';
+ }
+ if (strlen(hp->h_name) + 1 > hostlen)
+ return EAI_MEMORY;
+ strcpy(host, hp->h_name);
+ } else {
+ if (flags & NI_NAMEREQD)
+ return EAI_NONAME;
+ numeric:
+ switch(afd->a_af) {
+ case AF_INET6:
+ {
+ int error;
+
+ if ((error = ip6_parsenumeric(sa, addr, host,
+ hostlen,
+ flags)) != 0)
+ return(error);
+ break;
+ }
+
+ default:
+ if (inet_ntop(afd->a_af, addr, numaddr,
+ sizeof(numaddr)) == NULL)
+ return EAI_NONAME;
+ if (strlen(numaddr) + 1 > hostlen)
+ return EAI_MEMORY;
+ strcpy(host, numaddr);
+ }
+ }
+ }
+ return(0);
+}
+
+static int
+ip6_parsenumeric(const struct sockaddr *sa, const char *addr, char *host,
+ size_t hostlen, int flags)
+{
+ size_t numaddrlen;
+ char numaddr[512];
+
+#ifndef HAVE_SIN6_SCOPE_ID
+ UNUSED(sa);
+ UNUSED(flags);
+#endif
+
+ if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr))
+ == NULL)
+ return EAI_SYSTEM;
+
+ numaddrlen = strlen(numaddr);
+ if (numaddrlen + 1 > hostlen) /*%< don't forget terminator */
+ return EAI_MEMORY;
+ strcpy(host, numaddr);
+
+#ifdef HAVE_SIN6_SCOPE_ID
+ if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+ char scopebuf[MAXHOSTNAMELEN]; /*%< XXX */
+ int scopelen;
+
+ /* ip6_sa2str never fails */
+ scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa,
+ scopebuf, sizeof(scopebuf), flags);
+
+ if (scopelen + 1 + numaddrlen + 1 > hostlen)
+ return EAI_MEMORY;
+
+ /* construct <numeric-addr><delim><scopeid> */
+ memcpy(host + numaddrlen + 1, scopebuf,
+ scopelen);
+ host[numaddrlen] = SCOPE_DELIMITER;
+ host[numaddrlen + 1 + scopelen] = '\0';
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef HAVE_SIN6_SCOPE_ID
+/* ARGSUSED */
+static int
+ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf,
+ size_t bufsiz, int flags)
+{
+#ifdef USE_IFNAMELINKID
+ unsigned int ifindex = (unsigned int)sa6->sin6_scope_id;
+ const struct in6_addr *a6 = &sa6->sin6_addr;
+#endif
+ char tmp[64];
+
+#ifdef NI_NUMERICSCOPE
+ if (flags & NI_NUMERICSCOPE) {
+ sprintf(tmp, "%u", sa6->sin6_scope_id);
+ if (bufsiz != 0U) {
+ strncpy(buf, tmp, bufsiz - 1);
+ buf[bufsiz - 1] = '\0';
+ }
+ return(strlen(tmp));
+ }
+#endif
+
+#ifdef USE_IFNAMELINKID
+ /*
+ * For a link-local address, convert the index to an interface
+ * name, assuming a one-to-one mapping between links and interfaces.
+ * Note, however, that this assumption is stronger than the
+ * specification of the scoped address architecture; the
+ * specficication says that more than one interfaces can belong to
+ * a single link.
+ */
+
+ /* if_indextoname() does not take buffer size. not a good api... */
+ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) &&
+ bufsiz >= IF_NAMESIZE) {
+ char *p = if_indextoname(ifindex, buf);
+ if (p) {
+ return(strlen(p));
+ }
+ }
+#endif
+
+ /* last resort */
+ sprintf(tmp, "%u", sa6->sin6_scope_id);
+ if (bufsiz != 0U) {
+ strncpy(buf, tmp, bufsiz - 1);
+ buf[bufsiz - 1] = '\0';
+ }
+ return(strlen(tmp));
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getnetent.c b/usr/src/lib/libresolv2_joy/common/irs/getnetent.c
new file mode 100644
index 0000000000..0d00699e81
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getnetent.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getnetent.c,v 1.7 2005/04/27 04:56:25 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+ struct netent netent;
+ char * aliases[1];
+ char name[MAXDNAME + 1];
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static struct netent *nw_to_net(struct nwent *, struct net_data *);
+static void freepvt(struct net_data *);
+static struct netent *fakeaddr(const char *, int af, struct net_data *);
+
+/* Portability */
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
+/* Public */
+
+struct netent *
+getnetent() {
+ struct net_data *net_data = init();
+
+ return (getnetent_p(net_data));
+}
+
+struct netent *
+getnetbyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getnetbyname_p(name, net_data));
+}
+
+struct netent *
+getnetbyaddr(unsigned long net, int type) {
+ struct net_data *net_data = init();
+
+ return (getnetbyaddr_p(net, type, net_data));
+}
+
+void
+setnetent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setnetent_p(stayopen, net_data);
+}
+
+
+void
+endnetent() {
+ struct net_data *net_data = init();
+
+ endnetent_p(net_data);
+}
+
+/* Shared private. */
+
+struct netent *
+getnetent_p(struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ net_data->nww_last = (*nw->next)(nw);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyname_p(const char *name, struct net_data *net_data) {
+ struct irs_nw *nw;
+ struct netent *np;
+ char **nap;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ if (net_data->nw_stayopen && net_data->nw_last) {
+ if (!strcmp(net_data->nw_last->n_name, name))
+ return (net_data->nw_last);
+ for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++)
+ if (!strcmp(name, *nap))
+ return (net_data->nw_last);
+ }
+ if ((np = fakeaddr(name, AF_INET, net_data)) != NULL)
+ return (np);
+ net_data->nww_last = (*nw->byname)(nw, name, AF_INET);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ if (!net_data->nw_stayopen)
+ endnetent();
+ return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) {
+ struct irs_nw *nw;
+ u_char addr[4];
+ int bits;
+
+ if (!net_data || !(nw = net_data->nw))
+ return (NULL);
+ if (net_data->nw_stayopen && net_data->nw_last)
+ if (type == net_data->nw_last->n_addrtype &&
+ net == net_data->nw_last->n_net)
+ return (net_data->nw_last);
+
+ /* cannonize net(host order) */
+ if (net < 256UL) {
+ net <<= 24;
+ bits = 8;
+ } else if (net < 65536UL) {
+ net <<= 16;
+ bits = 16;
+ } else if (net < 16777216UL) {
+ net <<= 8;
+ bits = 24;
+ } else
+ bits = 32;
+
+ /* convert to net order */
+ addr[0] = (0xFF000000 & net) >> 24;
+ addr[1] = (0x00FF0000 & net) >> 16;
+ addr[2] = (0x0000FF00 & net) >> 8;
+ addr[3] = (0x000000FF & net);
+
+ /* reduce bits to as close to natural number as possible */
+ if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) {
+ if ((addr[0] < 192) && (addr[2] == 0)) {
+ if ((addr[0] < 128) && (addr[1] == 0))
+ bits = 8;
+ else
+ bits = 16;
+ } else {
+ bits = 24;
+ }
+ }
+
+ net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET);
+ net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+ if (!net_data->nw_stayopen)
+ endnetent();
+ return (net_data->nw_last);
+}
+
+
+
+
+void
+setnetent_p(int stayopen, struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if (!net_data || !(nw = net_data->nw))
+ return;
+ freepvt(net_data);
+ (*nw->rewind)(nw);
+ net_data->nw_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endnetent_p(struct net_data *net_data) {
+ struct irs_nw *nw;
+
+ if ((net_data != NULL) && ((nw = net_data->nw) != NULL))
+ (*nw->minimize)(nw);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->nw) {
+ net_data->nw = (*net_data->irs->nw_map)(net_data->irs);
+
+ if (!net_data->nw || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->nw->res_set)(net_data->nw, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+ if (net_data->nw_data) {
+ free(net_data->nw_data);
+ net_data->nw_data = NULL;
+ }
+}
+
+static struct netent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+ struct pvt *pvt;
+ const char *cp;
+ u_long tmp;
+
+ if (af != AF_INET) {
+ /* XXX should support IPv6 some day */
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (!isascii((unsigned char)(name[0])) ||
+ !isdigit((unsigned char)(name[0])))
+ return (NULL);
+ for (cp = name; *cp; ++cp)
+ if (!isascii(*cp) || (!isdigit((unsigned char)*cp) && *cp != '.'))
+ return (NULL);
+ if (*--cp == '.')
+ return (NULL);
+
+ /* All-numeric, no dot at the end. */
+
+ tmp = inet_network(name);
+ if (tmp == INADDR_NONE) {
+ RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+
+ /* Valid network number specified.
+ * Fake up a netent as if we'd actually
+ * done a lookup.
+ */
+ freepvt(net_data);
+ net_data->nw_data = malloc(sizeof (struct pvt));
+ if (!net_data->nw_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->nw_data;
+
+ strncpy(pvt->name, name, MAXDNAME);
+ pvt->name[MAXDNAME] = '\0';
+ pvt->netent.n_name = pvt->name;
+ pvt->netent.n_addrtype = AF_INET;
+ pvt->netent.n_aliases = pvt->aliases;
+ pvt->aliases[0] = NULL;
+ pvt->netent.n_net = tmp;
+
+ return (&pvt->netent);
+}
+
+static struct netent *
+nw_to_net(struct nwent *nwent, struct net_data *net_data) {
+ struct pvt *pvt;
+ u_long addr = 0;
+ int i;
+ int msbyte;
+
+ if (!nwent || nwent->n_addrtype != AF_INET)
+ return (NULL);
+ freepvt(net_data);
+ net_data->nw_data = malloc(sizeof (struct pvt));
+ if (!net_data->nw_data) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ pvt = net_data->nw_data;
+ pvt->netent.n_name = nwent->n_name;
+ pvt->netent.n_aliases = nwent->n_aliases;
+ pvt->netent.n_addrtype = nwent->n_addrtype;
+
+/*%
+ * What this code does: Converts net addresses from network to host form.
+ *
+ * msbyte: the index of the most significant byte in the n_addr array.
+ *
+ * Shift bytes in significant order into addr. When all signicant
+ * bytes are in, zero out bits in the LSB that are not part of the network.
+ */
+ msbyte = nwent->n_length / 8 +
+ ((nwent->n_length % 8) != 0 ? 1 : 0) - 1;
+ for (i = 0; i <= msbyte; i++)
+ addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i];
+ i = (32 - nwent->n_length) % 8;
+ if (i != 0)
+ addr &= ~((1 << (i + 1)) - 1);
+ pvt->netent.n_net = addr;
+ return (&pvt->netent);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getnetent_r.c b/usr/src/lib/libresolv2_joy/common/irs/getnetent_r.c
new file mode 100644
index 0000000000..9fb52bc394
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getnetent_r.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getnetent_r.c,v 1.6 2005/09/03 12:41:38 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getnetent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef NET_R_RETURN
+
+static NET_R_RETURN
+copy_netent(struct netent *, struct netent *, NET_R_COPY_ARGS);
+
+NET_R_RETURN
+getnetbyname_r(const char *name, struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetbyname(name);
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+#ifndef GETNETBYADDR_ADDR_T
+#define GETNETBYADDR_ADDR_T long
+#endif
+NET_R_RETURN
+getnetbyaddr_r(GETNETBYADDR_ADDR_T addr, int type, struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetbyaddr(addr, type);
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+NET_R_RETURN
+getnetent_r(struct netent *nptr, NET_R_ARGS) {
+ struct netent *ne = getnetent();
+#ifdef NET_R_SETANSWER
+ int n = 0;
+
+ if (ne == NULL || (n = copy_netent(ne, nptr, NET_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = ne;
+ if (ne == NULL)
+ *h_errnop = h_errno;
+ return (n);
+#else
+
+ if (ne == NULL)
+ return (NET_R_BAD);
+
+ return (copy_netent(ne, nptr, NET_R_COPY));
+#endif
+}
+
+NET_R_SET_RETURN
+#ifdef NET_R_ENT_ARGS
+setnetent_r(int stay_open, NET_R_ENT_ARGS)
+#else
+setnetent_r(int stay_open)
+#endif
+{
+#ifdef NET_R_ENT_ARGS
+ UNUSED(ndptr);
+#endif
+ setnetent(stay_open);
+#ifdef NET_R_SET_RESULT
+ return (NET_R_SET_RESULT);
+#endif
+}
+
+NET_R_END_RETURN
+#ifdef NET_R_ENT_ARGS
+endnetent_r(NET_R_ENT_ARGS)
+#else
+endnetent_r()
+#endif
+{
+#ifdef NET_R_ENT_ARGS
+ UNUSED(ndptr);
+#endif
+ endnetent();
+ NET_R_END_RESULT(NET_R_OK);
+}
+
+/* Private */
+
+#ifndef NETENT_DATA
+static NET_R_RETURN
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; ne->n_aliases[i]; i++, numptr++) {
+ len += strlen(ne->n_aliases[i]) + 1;
+ }
+ len += strlen(ne->n_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (NET_R_BAD);
+ }
+
+ /* copy net value and type */
+ nptr->n_addrtype = ne->n_addrtype;
+ nptr->n_net = ne->n_net;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(ne->n_name) + 1;
+ strcpy(cp, ne->n_name);
+ nptr->n_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ nptr->n_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; ne->n_aliases[i]; i++) {
+ n = strlen(ne->n_aliases[i]) + 1;
+ strcpy(cp, ne->n_aliases[i]);
+ nptr->n_aliases[i] = cp;
+ cp += n;
+ }
+ nptr->n_aliases[i] = NULL;
+
+ return (NET_R_OK);
+}
+#else /* !NETENT_DATA */
+static int
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy net value and type */
+ nptr->n_addrtype = ne->n_addrtype;
+ nptr->n_net = ne->n_net;
+
+ /* copy official name */
+ cp = ndptr->line;
+ eob = ndptr->line + sizeof(ndptr->line);
+ if ((n = strlen(ne->n_name) + 1) < (eob - cp)) {
+ strcpy(cp, ne->n_name);
+ nptr->n_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ nptr->n_aliases = ndptr->net_aliases;
+ while (ne->n_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(ne->n_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, ne->n_aliases[i]);
+ nptr->n_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ nptr->n_aliases[i] = NULL;
+
+ return (NET_R_OK);
+}
+#endif /* !NETENT_DATA */
+#else /* NET_R_RETURN */
+ static int getnetent_r_unknown_system = 0;
+#endif /* NET_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getnetgrent.c b/usr/src/lib/libresolv2_joy/common/irs/getnetgrent.c
new file mode 100644
index 0000000000..40b3e5a8ad
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getnetgrent.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getnetgrent.c,v 1.6 2008/11/14 02:36:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+
+/* Public */
+
+#ifndef SETNETGRENT_ARGS
+#define SETNETGRENT_ARGS const char *netgroup
+#endif
+void
+setnetgrent(SETNETGRENT_ARGS) {
+ struct net_data *net_data = init();
+
+ setnetgrent_p(netgroup, net_data);
+}
+
+void
+endnetgrent(void) {
+ struct net_data *net_data = init();
+
+ endnetgrent_p(net_data);
+}
+
+#ifndef INNETGR_ARGS
+#define INNETGR_ARGS const char *netgroup, const char *host, \
+ const char *user, const char *domain
+#endif
+int
+innetgr(INNETGR_ARGS) {
+ struct net_data *net_data = init();
+
+ return (innetgr_p(netgroup, host, user, domain, net_data));
+}
+
+int
+getnetgrent(NGR_R_CONST char **host, NGR_R_CONST char **user,
+ NGR_R_CONST char **domain)
+{
+ struct net_data *net_data = init();
+ const char *ch, *cu, *cd;
+ int ret;
+
+ ret = getnetgrent_p(&ch, &cu, &cd, net_data);
+ if (ret != 1)
+ return (ret);
+
+ DE_CONST(ch, *host);
+ DE_CONST(cu, *user);
+ DE_CONST(cd, *domain);
+ return (ret);
+}
+
+/* Shared private. */
+
+void
+setnetgrent_p(const char *netgroup, struct net_data *net_data) {
+ struct irs_ng *ng;
+
+ if ((net_data != NULL) && ((ng = net_data->ng) != NULL))
+ (*ng->rewind)(ng, netgroup);
+}
+
+void
+endnetgrent_p(struct net_data *net_data) {
+ struct irs_ng *ng;
+
+ if (!net_data)
+ return;
+ if ((ng = net_data->ng) != NULL)
+ (*ng->close)(ng);
+ net_data->ng = NULL;
+}
+
+int
+innetgr_p(const char *netgroup, const char *host,
+ const char *user, const char *domain,
+ struct net_data *net_data) {
+ struct irs_ng *ng;
+
+ if (!net_data || !(ng = net_data->ng))
+ return (0);
+ return ((*ng->test)(ng, netgroup, host, user, domain));
+}
+
+int
+getnetgrent_p(const char **host, const char **user, const char **domain,
+ struct net_data *net_data ) {
+ struct irs_ng *ng;
+
+ if (!net_data || !(ng = net_data->ng))
+ return (0);
+ return ((*ng->next)(ng, host, user, domain));
+}
+
+/* Private */
+
+static struct net_data *
+init(void) {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->ng) {
+ net_data->ng = (*net_data->irs->ng_map)(net_data->irs);
+ if (!net_data->ng) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ }
+
+ return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getnetgrent_r.c b/usr/src/lib/libresolv2_joy/common/irs/getnetgrent_r.c
new file mode 100644
index 0000000000..aa8810320d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getnetgrent_r.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getnetgrent_r.c,v 1.14 2008/11/14 02:36:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getnetgrent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <port_after.h>
+
+#ifdef NGR_R_RETURN
+#ifndef NGR_R_PRIVATE
+#define NGR_R_PRIVATE 0
+#endif
+
+static NGR_R_RETURN
+copy_protoent(NGR_R_CONST char **, NGR_R_CONST char **, NGR_R_CONST char **,
+ const char *, const char *, const char *, NGR_R_COPY_ARGS);
+
+NGR_R_RETURN
+innetgr_r(const char *netgroup, const char *host, const char *user,
+ const char *domain) {
+ char *ng, *ho, *us, *dom;
+
+ DE_CONST(netgroup, ng);
+ DE_CONST(host, ho);
+ DE_CONST(user, us);
+ DE_CONST(domain, dom);
+
+ return (innetgr(ng, ho, us, dom));
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+NGR_R_RETURN
+getnetgrent_r(NGR_R_CONST char **machinep, NGR_R_CONST char **userp,
+ NGR_R_CONST char **domainp, NGR_R_ARGS)
+{
+ NGR_R_CONST char *mp, *up, *dp;
+ int res = getnetgrent(&mp, &up, &dp);
+
+ if (res != 1)
+ return (res);
+
+ return (copy_protoent(machinep, userp, domainp,
+ mp, up, dp, NGR_R_COPY));
+}
+
+#if NGR_R_PRIVATE == 2
+struct private {
+ char *buf;
+};
+
+#endif
+NGR_R_SET_RETURN
+#ifdef NGR_R_SET_ARGS
+setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS)
+#else
+setnetgrent_r(NGR_R_SET_CONST char *netgroup)
+#endif
+{
+#if NGR_R_PRIVATE == 2
+ struct private *p;
+#endif
+ char *tmp;
+#if defined(NGR_R_SET_ARGS) && NGR_R_PRIVATE == 0
+ UNUSED(buf);
+ UNUSED(buflen);
+#endif
+
+ DE_CONST(netgroup, tmp);
+ setnetgrent(tmp);
+
+#if NGR_R_PRIVATE == 1
+ *buf = NULL;
+#elif NGR_R_PRIVATE == 2
+ *buf = p = malloc(sizeof(struct private));
+ if (p == NULL)
+#ifdef NGR_R_SET_RESULT
+ return (NGR_R_BAD);
+#else
+ return;
+#endif
+ p->buf = NULL;
+#endif
+#ifdef NGR_R_SET_RESULT
+ return (NGR_R_SET_RESULT);
+#endif
+}
+
+NGR_R_END_RETURN
+#ifdef NGR_R_END_ARGS
+endnetgrent_r(NGR_R_END_ARGS)
+#else
+endnetgrent_r(void)
+#endif
+{
+#if NGR_R_PRIVATE == 2
+ struct private *p = buf;
+#endif
+#if defined(NGR_R_SET_ARGS) && NGR_R_PRIVATE == 0
+ UNUSED(buf);
+ UNUSED(buflen);
+#endif
+
+ endnetgrent();
+#if NGR_R_PRIVATE == 1
+ if (*buf != NULL)
+ free(*buf);
+ *buf = NULL;
+#elif NGR_R_PRIVATE == 2
+ if (p->buf != NULL)
+ free(p->buf);
+ free(p);
+#endif
+ NGR_R_END_RESULT(NGR_R_OK);
+}
+
+/* Private */
+
+static int
+copy_protoent(NGR_R_CONST char **machinep, NGR_R_CONST char **userp,
+ NGR_R_CONST char **domainp, const char *mp, const char *up,
+ const char *dp, NGR_R_COPY_ARGS)
+{
+#if NGR_R_PRIVATE == 2
+ struct private *p = buf;
+#endif
+ char *cp;
+ int n;
+ int len;
+
+ /* Find out the amount of space required to store the answer. */
+ len = 0;
+ if (mp != NULL) len += strlen(mp) + 1;
+ if (up != NULL) len += strlen(up) + 1;
+ if (dp != NULL) len += strlen(dp) + 1;
+
+#if NGR_R_PRIVATE == 1
+ if (*buf != NULL)
+ free(*buf);
+ *buf = malloc(len);
+ if (*buf == NULL)
+ return(NGR_R_BAD);
+ cp = *buf;
+#elif NGR_R_PRIVATE == 2
+ if (p->buf)
+ free(p->buf);
+ p->buf = malloc(len);
+ if (p->buf == NULL)
+ return(NGR_R_BAD);
+ cp = p->buf;
+#else
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (NGR_R_BAD);
+ }
+ cp = buf;
+#endif
+
+ if (mp != NULL) {
+ n = strlen(mp) + 1;
+ strcpy(cp, mp);
+ *machinep = cp;
+ cp += n;
+ } else
+ *machinep = NULL;
+
+ if (up != NULL) {
+ n = strlen(up) + 1;
+ strcpy(cp, up);
+ *userp = cp;
+ cp += n;
+ } else
+ *userp = NULL;
+
+ if (dp != NULL) {
+ n = strlen(dp) + 1;
+ strcpy(cp, dp);
+ *domainp = cp;
+ cp += n;
+ } else
+ *domainp = NULL;
+
+ return (NGR_R_OK);
+}
+#else /* NGR_R_RETURN */
+ static int getnetgrent_r_unknown_system = 0;
+#endif /* NGR_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getprotoent.c b/usr/src/lib/libresolv2_joy/common/irs/getprotoent.c
new file mode 100644
index 0000000000..32a1040916
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getprotoent.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getprotoent.c,v 1.4 2005/04/27 04:56:26 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct protoent *
+getprotoent() {
+ struct net_data *net_data = init();
+
+ return (getprotoent_p(net_data));
+}
+
+struct protoent *
+getprotobyname(const char *name) {
+ struct net_data *net_data = init();
+
+ return (getprotobyname_p(name, net_data));
+}
+
+struct protoent *
+getprotobynumber(int proto) {
+ struct net_data *net_data = init();
+
+ return (getprotobynumber_p(proto, net_data));
+}
+
+void
+setprotoent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setprotoent_p(stayopen, net_data);
+}
+
+void
+endprotoent() {
+ struct net_data *net_data = init();
+
+ endprotoent_p(net_data);
+}
+
+/* Shared private. */
+
+struct protoent *
+getprotoent_p(struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ net_data->pr_last = (*pr->next)(pr);
+ return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobyname_p(const char *name, struct net_data *net_data) {
+ struct irs_pr *pr;
+ char **pap;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ if (net_data->pr_stayopen && net_data->pr_last) {
+ if (!strcmp(net_data->pr_last->p_name, name))
+ return (net_data->pr_last);
+ for (pap = net_data->pr_last->p_aliases; pap && *pap; pap++)
+ if (!strcmp(name, *pap))
+ return (net_data->pr_last);
+ }
+ net_data->pr_last = (*pr->byname)(pr, name);
+ if (!net_data->pr_stayopen)
+ endprotoent();
+ return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobynumber_p(int proto, struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return (NULL);
+ if (net_data->pr_stayopen && net_data->pr_last)
+ if (net_data->pr_last->p_proto == proto)
+ return (net_data->pr_last);
+ net_data->pr_last = (*pr->bynumber)(pr, proto);
+ if (!net_data->pr_stayopen)
+ endprotoent();
+ return (net_data->pr_last);
+}
+
+void
+setprotoent_p(int stayopen, struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if (!net_data || !(pr = net_data->pr))
+ return;
+ (*pr->rewind)(pr);
+ net_data->pr_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endprotoent_p(struct net_data *net_data) {
+ struct irs_pr *pr;
+
+ if ((net_data != NULL) && ((pr = net_data->pr) != NULL))
+ (*pr->minimize)(pr);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->pr) {
+ net_data->pr = (*net_data->irs->pr_map)(net_data->irs);
+
+ if (!net_data->pr || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->pr->res_set)(net_data->pr, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getprotoent_r.c b/usr/src/lib/libresolv2_joy/common/irs/getprotoent_r.c
new file mode 100644
index 0000000000..d5d9ae53b6
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getprotoent_r.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getprotoent_r.c,v 1.6 2006/08/01 01:14:16 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getprotoent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <port_after.h>
+
+#ifdef PROTO_R_RETURN
+
+static PROTO_R_RETURN
+copy_protoent(struct protoent *, struct protoent *, PROTO_R_COPY_ARGS);
+
+PROTO_R_RETURN
+getprotobyname_r(const char *name, struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotobyname(name);
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+PROTO_R_RETURN
+getprotobynumber_r(int proto, struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotobynumber(proto);
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+PROTO_R_RETURN
+getprotoent_r(struct protoent *pptr, PROTO_R_ARGS) {
+ struct protoent *pe = getprotoent();
+#ifdef PROTO_R_SETANSWER
+ int n = 0;
+
+ if (pe == NULL || (n = copy_protoent(pe, pptr, PROTO_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = pptr;
+
+ return (n);
+#else
+ if (pe == NULL)
+ return (PROTO_R_BAD);
+
+ return (copy_protoent(pe, pptr, PROTO_R_COPY));
+#endif
+}
+
+PROTO_R_SET_RETURN
+#ifdef PROTO_R_ENT_ARGS
+setprotoent_r(int stay_open, PROTO_R_ENT_ARGS)
+#else
+setprotoent_r(int stay_open)
+#endif
+{
+#ifdef PROTO_R_ENT_UNUSED
+ PROTO_R_ENT_UNUSED;
+#endif
+ setprotoent(stay_open);
+#ifdef PROTO_R_SET_RESULT
+ return (PROTO_R_SET_RESULT);
+#endif
+}
+
+PROTO_R_END_RETURN
+#ifdef PROTO_R_ENT_ARGS
+endprotoent_r(PROTO_R_ENT_ARGS)
+#else
+endprotoent_r()
+#endif
+{
+#ifdef PROTO_R_ENT_UNUSED
+ PROTO_R_ENT_UNUSED;
+#endif
+ endprotoent();
+ PROTO_R_END_RESULT(PROTO_R_OK);
+}
+
+/* Private */
+
+#ifndef PROTOENT_DATA
+static PROTO_R_RETURN
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; pe->p_aliases[i]; i++, numptr++) {
+ len += strlen(pe->p_aliases[i]) + 1;
+ }
+ len += strlen(pe->p_name) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (PROTO_R_BAD);
+ }
+
+ /* copy protocol value*/
+ pptr->p_proto = pe->p_proto;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(pe->p_name) + 1;
+ strcpy(cp, pe->p_name);
+ pptr->p_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ pptr->p_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; pe->p_aliases[i]; i++) {
+ n = strlen(pe->p_aliases[i]) + 1;
+ strcpy(cp, pe->p_aliases[i]);
+ pptr->p_aliases[i] = cp;
+ cp += n;
+ }
+ pptr->p_aliases[i] = NULL;
+
+ return (PROTO_R_OK);
+}
+#else /* !PROTOENT_DATA */
+static int
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy protocol value */
+ pptr->p_proto = pe->p_proto;
+
+ /* copy official name */
+ cp = pdptr->line;
+ eob = pdptr->line + sizeof(pdptr->line);
+ if ((n = strlen(pe->p_name) + 1) < (eob - cp)) {
+ strcpy(cp, pe->p_name);
+ pptr->p_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ pptr->p_aliases = pdptr->proto_aliases;
+ while (pe->p_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(pe->p_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, pe->p_aliases[i]);
+ pptr->p_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ pptr->p_aliases[i] = NULL;
+
+ return (PROTO_R_OK);
+}
+#endif /* PROTOENT_DATA */
+#else /* PROTO_R_RETURN */
+ static int getprotoent_r_unknown_system = 0;
+#endif /* PROTO_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getservent.c b/usr/src/lib/libresolv2_joy/common/irs/getservent.c
new file mode 100644
index 0000000000..31af67e659
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getservent.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getservent.c,v 1.4 2005/04/27 04:56:26 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct servent *
+getservent(void) {
+ struct net_data *net_data = init();
+
+ return (getservent_p(net_data));
+}
+
+struct servent *
+getservbyname(const char *name, const char *proto) {
+ struct net_data *net_data = init();
+
+ return (getservbyname_p(name, proto, net_data));
+}
+
+struct servent *
+getservbyport(int port, const char *proto) {
+ struct net_data *net_data = init();
+
+ return (getservbyport_p(port, proto, net_data));
+}
+
+void
+setservent(int stayopen) {
+ struct net_data *net_data = init();
+
+ setservent_p(stayopen, net_data);
+}
+
+void
+endservent() {
+ struct net_data *net_data = init();
+
+ endservent_p(net_data);
+}
+
+/* Shared private. */
+
+struct servent *
+getservent_p(struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ net_data->sv_last = (*sv->next)(sv);
+ return (net_data->sv_last);
+}
+
+struct servent *
+getservbyname_p(const char *name, const char *proto,
+ struct net_data *net_data) {
+ struct irs_sv *sv;
+ char **sap;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ if (net_data->sv_stayopen && net_data->sv_last)
+ if (!proto || !strcmp(net_data->sv_last->s_proto, proto)) {
+ if (!strcmp(net_data->sv_last->s_name, name))
+ return (net_data->sv_last);
+ for (sap = net_data->sv_last->s_aliases;
+ sap && *sap; sap++)
+ if (!strcmp(name, *sap))
+ return (net_data->sv_last);
+ }
+ net_data->sv_last = (*sv->byname)(sv, name, proto);
+ if (!net_data->sv_stayopen)
+ endservent();
+ return (net_data->sv_last);
+}
+
+struct servent *
+getservbyport_p(int port, const char *proto, struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return (NULL);
+ if (net_data->sv_stayopen && net_data->sv_last)
+ if (port == net_data->sv_last->s_port &&
+ ( !proto ||
+ !strcmp(net_data->sv_last->s_proto, proto)))
+ return (net_data->sv_last);
+ net_data->sv_last = (*sv->byport)(sv, port, proto);
+ return (net_data->sv_last);
+}
+
+void
+setservent_p(int stayopen, struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if (!net_data || !(sv = net_data->sv))
+ return;
+ (*sv->rewind)(sv);
+ net_data->sv_stayopen = (stayopen != 0);
+ if (stayopen == 0)
+ net_data_minimize(net_data);
+}
+
+void
+endservent_p(struct net_data *net_data) {
+ struct irs_sv *sv;
+
+ if ((net_data != NULL) && ((sv = net_data->sv) != NULL))
+ (*sv->minimize)(sv);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+ struct net_data *net_data;
+
+ if (!(net_data = net_data_init(NULL)))
+ goto error;
+ if (!net_data->sv) {
+ net_data->sv = (*net_data->irs->sv_map)(net_data->irs);
+
+ if (!net_data->sv || !net_data->res) {
+ error:
+ errno = EIO;
+ return (NULL);
+ }
+ (*net_data->sv->res_set)(net_data->sv, net_data->res, NULL);
+ }
+
+ return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/getservent_r.c b/usr/src/lib/libresolv2_joy/common/irs/getservent_r.c
new file mode 100644
index 0000000000..42d1e46163
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/getservent_r.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: getservent_r.c,v 1.6 2006/08/01 01:14:16 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+ static int getservent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef SERV_R_RETURN
+
+static SERV_R_RETURN
+copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS);
+
+SERV_R_RETURN
+getservbyname_r(const char *name, const char *proto,
+ struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservbyname(name, proto);
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+SERV_R_RETURN
+getservbyport_r(int port, const char *proto,
+ struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservbyport(port, proto);
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+/*%
+ * These assume a single context is in operation per thread.
+ * If this is not the case we will need to call irs directly
+ * rather than through the base functions.
+ */
+
+SERV_R_RETURN
+getservent_r(struct servent *sptr, SERV_R_ARGS) {
+ struct servent *se = getservent();
+#ifdef SERV_R_SETANSWER
+ int n = 0;
+
+ if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
+ *answerp = NULL;
+ else
+ *answerp = sptr;
+
+ return (n);
+#else
+ if (se == NULL)
+ return (SERV_R_BAD);
+
+ return (copy_servent(se, sptr, SERV_R_COPY));
+#endif
+}
+
+SERV_R_SET_RETURN
+#ifdef SERV_R_ENT_ARGS
+setservent_r(int stay_open, SERV_R_ENT_ARGS)
+#else
+setservent_r(int stay_open)
+#endif
+{
+#ifdef SERV_R_ENT_UNUSED
+ SERV_R_ENT_UNUSED;
+#endif
+ setservent(stay_open);
+#ifdef SERV_R_SET_RESULT
+ return (SERV_R_SET_RESULT);
+#endif
+}
+
+SERV_R_END_RETURN
+#ifdef SERV_R_ENT_ARGS
+endservent_r(SERV_R_ENT_ARGS)
+#else
+endservent_r()
+#endif
+{
+#ifdef SERV_R_ENT_UNUSED
+ SERV_R_ENT_UNUSED;
+#endif
+ endservent();
+ SERV_R_END_RESULT(SERV_R_OK);
+}
+
+/* Private */
+
+#ifndef SERVENT_DATA
+static SERV_R_RETURN
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+ char *cp;
+ int i, n;
+ int numptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ numptr = 1; /*%< NULL ptr */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; se->s_aliases[i]; i++, numptr++) {
+ len += strlen(se->s_aliases[i]) + 1;
+ }
+ len += strlen(se->s_name) + 1;
+ len += strlen(se->s_proto) + 1;
+ len += numptr * sizeof(char*);
+
+ if (len > (int)buflen) {
+ errno = ERANGE;
+ return (SERV_R_BAD);
+ }
+
+ /* copy port value */
+ sptr->s_port = se->s_port;
+
+ cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+ /* copy official name */
+ n = strlen(se->s_name) + 1;
+ strcpy(cp, se->s_name);
+ sptr->s_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ sptr->s_aliases = (char **)ALIGN(buf);
+ for (i = 0 ; se->s_aliases[i]; i++) {
+ n = strlen(se->s_aliases[i]) + 1;
+ strcpy(cp, se->s_aliases[i]);
+ sptr->s_aliases[i] = cp;
+ cp += n;
+ }
+ sptr->s_aliases[i] = NULL;
+
+ /* copy proto */
+ n = strlen(se->s_proto) + 1;
+ strcpy(cp, se->s_proto);
+ sptr->s_proto = cp;
+ cp += n;
+
+ return (SERV_R_OK);
+}
+#else /* !SERVENT_DATA */
+static int
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+ char *cp, *eob;
+ int i, n;
+
+ /* copy port value */
+ sptr->s_port = se->s_port;
+
+ /* copy official name */
+ cp = sdptr->line;
+ eob = sdptr->line + sizeof(sdptr->line);
+ if ((n = strlen(se->s_name) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_name);
+ sptr->s_name = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ /* copy aliases */
+ i = 0;
+ sptr->s_aliases = sdptr->serv_aliases;
+ while (se->s_aliases[i] && i < (_MAXALIASES-1)) {
+ if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_aliases[i]);
+ sptr->s_aliases[i] = cp;
+ cp += n;
+ } else {
+ break;
+ }
+ i++;
+ }
+ sptr->s_aliases[i] = NULL;
+
+ /* copy proto */
+ if ((n = strlen(se->s_proto) + 1) < (eob - cp)) {
+ strcpy(cp, se->s_proto);
+ sptr->s_proto = cp;
+ cp += n;
+ } else {
+ return (-1);
+ }
+
+ return (SERV_R_OK);
+}
+#endif /* !SERVENT_DATA */
+#else /*SERV_R_RETURN */
+ static int getservent_r_unknown_system = 0;
+#endif /*SERV_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/hesiod.c b/usr/src/lib/libresolv2_joy/common/irs/hesiod.c
new file mode 100644
index 0000000000..7641bf80ac
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/hesiod.c
@@ -0,0 +1,505 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: hesiod.c,v 1.7 2005/07/28 06:51:48 marka Exp $";
+#endif
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*! \file
+ * \brief
+ * hesiod.c --- the core portion of the hesiod resolver.
+ *
+ * This file is derived from the hesiod library from Project Athena;
+ * It has been extensively rewritten by Theodore Ts'o to have a more
+ * thread-safe interface.
+ * \author
+ * This file is primarily maintained by &lt;tytso@mit.edu&gt; and &lt;ghudson@mit.edu&gt;.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#include "pathnames.h"
+#include "hesiod.h"
+#include "hesiod_p.h"
+
+/* Forward */
+
+int hesiod_init(void **context);
+void hesiod_end(void *context);
+char * hesiod_to_bind(void *context, const char *name,
+ const char *type);
+char ** hesiod_resolve(void *context, const char *name,
+ const char *type);
+void hesiod_free_list(void *context, char **list);
+
+static int parse_config_file(struct hesiod_p *ctx, const char *filename);
+static char ** get_txt_records(struct hesiod_p *ctx, int class,
+ const char *name);
+static int init(struct hesiod_p *ctx);
+
+/* Public */
+
+/*%
+ * This function is called to initialize a hesiod_p.
+ */
+int
+hesiod_init(void **context) {
+ struct hesiod_p *ctx;
+ char *cp;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx == 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ memset(ctx, 0, sizeof (*ctx));
+
+ if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) {
+#ifdef DEF_RHS
+ /*
+ * Use compiled in defaults.
+ */
+ ctx->LHS = malloc(strlen(DEF_LHS) + 1);
+ ctx->RHS = malloc(strlen(DEF_RHS) + 1);
+ if (ctx->LHS == NULL || ctx->RHS == NULL) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(ctx->LHS, DEF_LHS); /* (checked) */
+ strcpy(ctx->RHS, DEF_RHS); /* (checked) */
+#else
+ goto cleanup;
+#endif
+ }
+ /*
+ * The default RHS can be overridden by an environment
+ * variable.
+ */
+ if ((cp = getenv("HES_DOMAIN")) != NULL) {
+ size_t RHSlen = strlen(cp) + 2;
+ if (ctx->RHS)
+ free(ctx->RHS);
+ ctx->RHS = malloc(RHSlen);
+ if (!ctx->RHS) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ if (cp[0] == '.') {
+ strcpy(ctx->RHS, cp); /* (checked) */
+ } else {
+ strcpy(ctx->RHS, "."); /* (checked) */
+ strcat(ctx->RHS, cp); /* (checked) */
+ }
+ }
+
+ /*
+ * If there is no default hesiod realm set, we return an
+ * error.
+ */
+ if (!ctx->RHS) {
+ errno = ENOEXEC;
+ goto cleanup;
+ }
+
+#if 0
+ if (res_ninit(ctx->res) < 0)
+ goto cleanup;
+#endif
+
+ *context = ctx;
+ return (0);
+
+ cleanup:
+ hesiod_end(ctx);
+ return (-1);
+}
+
+/*%
+ * This function deallocates the hesiod_p
+ */
+void
+hesiod_end(void *context) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ int save_errno = errno;
+
+ if (ctx->res)
+ res_nclose(ctx->res);
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ if (ctx->res && ctx->free_res)
+ (*ctx->free_res)(ctx->res);
+ free(ctx);
+ errno = save_errno;
+}
+
+/*%
+ * This function takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname;
+ char **rhs_list = NULL;
+ const char *RHS, *cp;
+
+ /* Decide what our RHS is, and set cp to the end of the actual name. */
+ if ((cp = strchr(name, '@')) != NULL) {
+ if (strchr(cp + 1, '.'))
+ RHS = cp + 1;
+ else if ((rhs_list = hesiod_resolve(context, cp + 1,
+ "rhs-extension")) != NULL)
+ RHS = *rhs_list;
+ else {
+ errno = ENOENT;
+ return (NULL);
+ }
+ } else {
+ RHS = ctx->RHS;
+ cp = name + strlen(name);
+ }
+
+ /*
+ * Allocate the space we need, including up to three periods and
+ * the terminating NUL.
+ */
+ if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
+ (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
+ errno = ENOMEM;
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ return NULL;
+ }
+
+ /* Now put together the DNS name. */
+ memcpy(bindname, name, cp - name);
+ bindname[cp - name] = '\0';
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ if (ctx->LHS) {
+ if (ctx->LHS[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->LHS);
+ }
+ if (RHS[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, RHS);
+
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ return (bindname);
+}
+
+/*%
+ * This is the core function. Given a hesiod (name, type), it
+ * returns an array of strings returned by the resolver.
+ */
+char **
+hesiod_resolve(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname = hesiod_to_bind(context, name, type);
+ char **retvec;
+
+ if (bindname == NULL)
+ return (NULL);
+ if (init(ctx) == -1) {
+ free(bindname);
+ return (NULL);
+ }
+
+ if ((retvec = get_txt_records(ctx, C_IN, bindname))) {
+ free(bindname);
+ return (retvec);
+ }
+
+ if (errno != ENOENT)
+ return (NULL);
+
+ retvec = get_txt_records(ctx, C_HS, bindname);
+ free(bindname);
+ return (retvec);
+}
+
+void
+hesiod_free_list(void *context, char **list) {
+ char **p;
+
+ UNUSED(context);
+
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+/*%
+ * This function parses the /etc/hesiod.conf file
+ */
+static int
+parse_config_file(struct hesiod_p *ctx, const char *filename) {
+ char *key, *data, *cp, **cpp;
+ char buf[MAXDNAME+7];
+ FILE *fp;
+
+ /*
+ * Clear the existing configuration variable, just in case
+ * they're set.
+ */
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+
+ /*
+ * Now open and parse the file...
+ */
+ if (!(fp = fopen(filename, "r")))
+ return (-1);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ cp = buf;
+ if (*cp == '#' || *cp == '\n' || *cp == '\r')
+ continue;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ key = cp;
+ while(*cp != ' ' && *cp != '\t' && *cp != '=')
+ cp++;
+ *cp++ = '\0';
+
+ while(*cp == ' ' || *cp == '\t' || *cp == '=')
+ cp++;
+ data = cp;
+ while(*cp != ' ' && *cp != '\n' && *cp != '\r')
+ cp++;
+ *cp++ = '\0';
+
+ if (strcmp(key, "lhs") == 0)
+ cpp = &ctx->LHS;
+ else if (strcmp(key, "rhs") == 0)
+ cpp = &ctx->RHS;
+ else
+ continue;
+
+ *cpp = malloc(strlen(data) + 1);
+ if (!*cpp) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ strcpy(*cpp, data);
+ }
+ fclose(fp);
+ return (0);
+
+ cleanup:
+ fclose(fp);
+ if (ctx->RHS)
+ free(ctx->RHS);
+ if (ctx->LHS)
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+ return (-1);
+}
+
+/*%
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
+ struct {
+ int type; /*%< RR type */
+ int class; /*%< RR class */
+ int dlen; /*%< len of data section */
+ u_char *data; /*%< pointer to data */
+ } rr;
+ HEADER *hp;
+ u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
+ u_char *cp, *erdata, *eom;
+ char *dst, *edst, **list;
+ int ancount, qdcount;
+ int i, j, n, skip;
+
+ /*
+ * Construct the query and send it.
+ */
+ n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
+ NULL, qbuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = ECONNREFUSED;
+ return (NULL);
+ }
+ if (n < HFIXEDSZ) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+
+ /*
+ * OK, parse the result.
+ */
+ hp = (HEADER *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ cp = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /* Skip query, trying to get to the answer section which follows. */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return (NULL);
+ }
+ cp += skip + QFIXEDSZ;
+ }
+
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ cp += skip;
+ if (cp + 3 * INT16SZ + INT32SZ > eom) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ rr.type = ns_get16(cp);
+ cp += INT16SZ;
+ rr.class = ns_get16(cp);
+ cp += INT16SZ + INT32SZ; /*%< skip the ttl, too */
+ rr.dlen = ns_get16(cp);
+ cp += INT16SZ;
+ if (cp + rr.dlen > eom) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ rr.data = cp;
+ cp += rr.dlen;
+ if (rr.class != class || rr.type != T_TXT)
+ continue;
+ if (!(list[j] = malloc(rr.dlen)))
+ goto cleanup;
+ dst = list[j++];
+ edst = dst + rr.dlen;
+ erdata = rr.data + rr.dlen;
+ cp = rr.data;
+ while (cp < erdata) {
+ n = (unsigned char) *cp++;
+ if (cp + n > eom || dst + n > edst) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ memcpy(dst, cp, n);
+ cp += n;
+ dst += n;
+ }
+ if (cp != erdata) {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ *dst = '\0';
+ }
+ list[j] = NULL;
+ if (j == 0) {
+ errno = ENOENT;
+ goto cleanup;
+ }
+ return (list);
+
+ cleanup:
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return (NULL);
+}
+
+struct __res_state *
+__hesiod_res_get(void *context) {
+ struct hesiod_p *ctx = context;
+
+ if (!ctx->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ __hesiod_res_set(ctx, res, free);
+ }
+
+ return (ctx->res);
+}
+
+void
+__hesiod_res_set(void *context, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct hesiod_p *ctx = context;
+
+ if (ctx->res && ctx->free_res) {
+ res_nclose(ctx->res);
+ (*ctx->free_res)(ctx->res);
+ }
+
+ ctx->res = res;
+ ctx->free_res = free_res;
+}
+
+static int
+init(struct hesiod_p *ctx) {
+
+ if (!ctx->res && !__hesiod_res_get(ctx))
+ return (-1);
+
+ if (((ctx->res->options & RES_INIT) == 0U) &&
+ (res_ninit(ctx->res) == -1))
+ return (-1);
+
+ return (0);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/irs/hesiod_p.h b/usr/src/lib/libresolv2_joy/common/irs/hesiod_p.h
new file mode 100644
index 0000000000..99da15d0cd
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/hesiod_p.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: hesiod_p.h,v 1.3 2005/04/27 04:56:27 sra Exp $
+ */
+
+#ifndef _HESIOD_P_H_INCLUDED
+#define _HESIOD_P_H_INCLUDED
+
+/** \file
+ * \brief
+ * hesiod_p.h -- private definitions for the hesiod library.
+ *
+ * \author
+ * This file is primarily maintained by tytso@mit.edu and ghudson@mit.edu.
+ */
+
+#define DEF_RHS ".Athena.MIT.EDU" /*%< Defaults if HESIOD_CONF */
+#define DEF_LHS ".ns" /*%< file is not */
+ /*%< present. */
+struct hesiod_p {
+ char * LHS; /*%< normally ".ns" */
+ char * RHS; /*%< AKA the default hesiod domain */
+ struct __res_state * res; /*%< resolver context */
+ void (*free_res)(void *);
+ void (*res_set)(struct hesiod_p *, struct __res_state *,
+ void (*)(void *));
+ struct __res_state * (*res_get)(struct hesiod_p *);
+};
+
+#define MAX_HESRESP 1024
+
+#endif /*_HESIOD_P_H_INCLUDED*/
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp.c b/usr/src/lib/libresolv2_joy/common/irs/irp.c
new file mode 100644
index 0000000000..ef10631c22
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996, 1998-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irp.c,v 1.12 2008/11/14 02:36:51 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+#include <irp.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void irp_close(struct irs_acc *);
+
+#define LINEINCR 128
+
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+
+/* Public */
+
+
+/* send errors to syslog if true. */
+int irp_log_errors = 1;
+
+/*%
+ * This module handles the irp module connection to irpd.
+ *
+ * The client expects a synchronous interface to functions like
+ * getpwnam(3), so we can't use the ctl_* i/o library on this end of
+ * the wire (it's used in the server).
+ */
+
+/*%
+ * irs_acc *irs_irp_acc(const char *options);
+ *
+ * Initialize the irp module.
+ */
+struct irs_acc *
+irs_irp_acc(const char *options) {
+ struct irs_acc *acc;
+ struct irp_p *irp;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(irp = memget(sizeof *irp))) {
+ errno = ENOMEM;
+ free(acc);
+ return (NULL);
+ }
+ irp->inlast = 0;
+ irp->incurr = 0;
+ irp->fdCxn = -1;
+ acc->private = irp;
+
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_irp_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_irp_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_irp_sv;
+ acc->pr_map = irs_irp_pr;
+ acc->ho_map = irs_irp_ho;
+ acc->nw_map = irs_irp_nw;
+ acc->ng_map = irs_irp_ng;
+ acc->close = irp_close;
+ return (acc);
+}
+
+
+int
+irs_irp_connection_setup(struct irp_p *cxndata, int *warned) {
+ if (irs_irp_is_connected(cxndata)) {
+ return (0);
+ } else if (irs_irp_connect(cxndata) != 0) {
+ if (warned != NULL && !*warned) {
+ syslog(LOG_ERR, "irpd connection failed: %m\n");
+ (*warned)++;
+ }
+
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_connect(void);
+ *
+ * Sets up the connection to the remote irpd server.
+ *
+ * Returns:
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+int
+irs_irp_connect(struct irp_p *pvt) {
+ int flags;
+ struct sockaddr *addr;
+ struct sockaddr_in iaddr;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un uaddr;
+#endif
+ long ipaddr;
+ const char *irphost;
+ int code;
+ char text[256];
+ int socklen = 0;
+
+ if (pvt->fdCxn != -1) {
+ perror("fd != 1");
+ return (-1);
+ }
+
+#ifndef NO_SOCKADDR_UN
+ memset(&uaddr, 0, sizeof uaddr);
+#endif
+ memset(&iaddr, 0, sizeof iaddr);
+
+ irphost = getenv(IRPD_HOST_ENV);
+ if (irphost == NULL) {
+ irphost = "127.0.0.1";
+ }
+
+#ifndef NO_SOCKADDR_UN
+ if (irphost[0] == '/') {
+ addr = (struct sockaddr *)&uaddr;
+ strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path);
+ uaddr.sun_family = AF_UNIX;
+ socklen = SUN_LEN(&uaddr);
+#ifdef HAVE_SA_LEN
+ uaddr.sun_len = socklen;
+#endif
+ } else
+#endif
+ {
+ if (inet_pton(AF_INET, irphost, &ipaddr) != 1) {
+ errno = EADDRNOTAVAIL;
+ perror("inet_pton");
+ return (-1);
+ }
+
+ addr = (struct sockaddr *)&iaddr;
+ socklen = sizeof iaddr;
+#ifdef HAVE_SA_LEN
+ iaddr.sin_len = socklen;
+#endif
+ iaddr.sin_family = AF_INET;
+ iaddr.sin_port = htons(IRPD_PORT);
+ iaddr.sin_addr.s_addr = ipaddr;
+ }
+
+
+ pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (pvt->fdCxn < 0) {
+ perror("socket");
+ return (-1);
+ }
+
+ if (connect(pvt->fdCxn, addr, socklen) != 0) {
+ perror("connect");
+ return (-1);
+ }
+
+ flags = fcntl(pvt->fdCxn, F_GETFL, 0);
+ if (flags < 0) {
+ close(pvt->fdCxn);
+ perror("close");
+ return (-1);
+ }
+
+#if 0
+ flags |= O_NONBLOCK;
+ if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) {
+ close(pvt->fdCxn);
+ perror("fcntl");
+ return (-1);
+ }
+#endif
+
+ code = irs_irp_read_response(pvt, text, sizeof text);
+ if (code != IRPD_WELCOME_CODE) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "Connection failed: %s", text);
+ }
+ irs_irp_disconnect(pvt);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_is_connected(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ * Non-zero if streams are setup to remote.
+ *
+ */
+
+int
+irs_irp_is_connected(struct irp_p *pvt) {
+ return (pvt->fdCxn >= 0);
+}
+
+/*%
+ * void
+ * irs_irp_disconnect(struct irp_p *pvt);
+ *
+ * Closes streams to remote.
+ */
+
+void
+irs_irp_disconnect(struct irp_p *pvt) {
+ if (pvt->fdCxn != -1) {
+ close(pvt->fdCxn);
+ pvt->fdCxn = -1;
+ }
+}
+
+
+
+int
+irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) {
+ char *realstart = &pvt->inbuffer[0];
+ char *p, *start, *end;
+ int spare;
+ int i;
+ int buffpos = 0;
+ int left = len - 1;
+
+ while (left > 0) {
+ start = p = &pvt->inbuffer[pvt->incurr];
+ end = &pvt->inbuffer[pvt->inlast];
+
+ while (p != end && *p != '\n')
+ p++;
+
+ if (p == end) {
+ /* Found no newline so shift data down if necessary
+ * and append new data to buffer
+ */
+ if (start > realstart) {
+ memmove(realstart, start, end - start);
+ pvt->inlast = end - start;
+ start = realstart;
+ pvt->incurr = 0;
+ end = &pvt->inbuffer[pvt->inlast];
+ }
+
+ spare = sizeof (pvt->inbuffer) - pvt->inlast;
+
+ p = end;
+ i = read(pvt->fdCxn, end, spare);
+ if (i < 0) {
+ close(pvt->fdCxn);
+ pvt->fdCxn = -1;
+ return (buffpos > 0 ? buffpos : -1);
+ } else if (i == 0) {
+ return (buffpos);
+ }
+
+ end += i;
+ pvt->inlast += i;
+
+ while (p != end && *p != '\n')
+ p++;
+ }
+
+ if (p == end) {
+ /* full buffer and still no newline */
+ i = sizeof pvt->inbuffer;
+ } else {
+ /* include newline */
+ i = p - start + 1;
+ }
+
+ if (i > left)
+ i = left;
+ memcpy(buffer + buffpos, start, i);
+ pvt->incurr += i;
+ buffpos += i;
+ buffer[buffpos] = '\0';
+
+ if (p != end) {
+ left = 0;
+ } else {
+ left -= i;
+ }
+ }
+
+#if 0
+ fprintf(stderr, "read line: %s\n", buffer);
+#endif
+ return (buffpos);
+}
+
+/*%
+ * int irp_read_response(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ * The number found at the beginning of the line read from
+ * FP. 0 on failure(0 is not a legal response code). The
+ * rest of the line is discarded.
+ *
+ */
+
+int
+irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) {
+ char line[1024];
+ int code;
+ char *p;
+
+ if (irs_irp_read_line(pvt, line, sizeof line) <= 0) {
+ return (0);
+ }
+
+ p = strchr(line, '\n');
+ if (p == NULL) {
+ return (0);
+ }
+
+ if (sscanf(line, "%d", &code) != 1) {
+ code = 0;
+ } else if (text != NULL && textlen > 0U) {
+ p = line;
+ while (isspace((unsigned char)*p)) p++;
+ while (isdigit((unsigned char)*p)) p++;
+ while (isspace((unsigned char)*p)) p++;
+ strncpy(text, p, textlen - 1);
+ p[textlen - 1] = '\0';
+ }
+
+ return (code);
+}
+
+/*%
+ * char *irp_read_body(struct irp_p *pvt, size_t *size);
+ *
+ * Read in the body of a response. Terminated by a line with
+ * just a dot on it. Lines should be terminated with a CR-LF
+ * sequence, but we're nt piccky if the CR is missing.
+ * No leading dot escaping is done as the protcol doesn't
+ * use leading dots anywhere.
+ *
+ * Returns:
+ *
+ * Pointer to null-terminated buffer allocated by memget.
+ * *SIZE is set to the length of the buffer.
+ *
+ */
+
+char *
+irs_irp_read_body(struct irp_p *pvt, size_t *size) {
+ char line[1024];
+ u_int linelen;
+ size_t len = LINEINCR;
+ char *buffer = memget(len);
+ int idx = 0;
+
+ if (buffer == NULL)
+ return (NULL);
+
+ for (;;) {
+ if (irs_irp_read_line(pvt, line, sizeof line) <= 0 ||
+ strchr(line, '\n') == NULL)
+ goto death;
+
+ linelen = strlen(line);
+
+ if (line[linelen - 1] != '\n')
+ goto death;
+
+ /* We're not strict about missing \r. Should we be?? */
+ if (linelen > 2 && line[linelen - 2] == '\r') {
+ line[linelen - 2] = '\n';
+ line[linelen - 1] = '\0';
+ linelen--;
+ }
+
+ if (linelen == 2 && line[0] == '.') {
+ *size = len;
+ buffer[idx] = '\0';
+
+ return (buffer);
+ }
+
+ if (linelen > (len - (idx + 1))) {
+ char *p = memget(len + LINEINCR);
+
+ if (p == NULL)
+ goto death;
+ memcpy(p, buffer, len);
+ memput(buffer, len);
+ buffer = p;
+ len += LINEINCR;
+ }
+
+ memcpy(buffer + idx, line, linelen);
+ idx += linelen;
+ }
+ death:
+ memput(buffer, len);
+ return (NULL);
+}
+
+/*%
+ * int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+ * char **body, size_t *bodylen);
+ *
+ * Gets the response to a command. If the response indicates
+ * there's a body to follow(code % 10 == 1), then the
+ * body buffer is allcoated with memget and stored in
+ * *BODY. The length of the allocated body buffer is stored
+ * in *BODY. The caller must give the body buffer back to
+ * memput when done. The results code is stored in *CODE.
+ *
+ * Returns:
+ *
+ * 0 if a result was read. -1 on some sort of failure.
+ *
+ */
+
+int
+irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text,
+ size_t textlen, char **body, size_t *bodylen) {
+ int result = irs_irp_read_response(pvt, text, textlen);
+
+ *body = NULL;
+
+ if (result == 0) {
+ return (-1);
+ }
+
+ *code = result;
+
+ /* Code that matches 2xx is a good result code.
+ * Code that matches xx1 means there's a response body coming.
+ */
+ if ((result / 100) == 2 && (result % 10) == 1) {
+ *body = irs_irp_read_body(pvt, bodylen);
+ if (*body == NULL) {
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+/*%
+ * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
+ *
+ * Sends command to remote connected via the PVT
+ * structure. FMT and args after it are fprintf-like
+ * arguments for formatting.
+ *
+ * Returns:
+ *
+ * 0 on success, -1 on failure.
+ */
+
+int
+irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) {
+ va_list ap;
+ char buffer[1024];
+ int pos = 0;
+ int i, todo;
+
+
+ if (pvt->fdCxn < 0) {
+ return (-1);
+ }
+
+ va_start(ap, fmt);
+ (void) vsprintf(buffer, fmt, ap);
+ todo = strlen(buffer);
+ va_end(ap);
+ if (todo > (int)sizeof(buffer) - 3) {
+ syslog(LOG_CRIT, "memory overrun in irs_irp_send_command()");
+ exit(1);
+ }
+ strcat(buffer, "\r\n");
+ todo = strlen(buffer);
+
+ while (todo > 0) {
+ i = write(pvt->fdCxn, buffer + pos, todo);
+#if 0
+ /* XXX brister */
+ fprintf(stderr, "Wrote: \"");
+ fwrite(buffer + pos, sizeof (char), todo, stderr);
+ fprintf(stderr, "\"\n");
+#endif
+ if (i < 0) {
+ close(pvt->fdCxn);
+ pvt->fdCxn = -1;
+ return (-1);
+ }
+ todo -= i;
+ }
+
+ return (0);
+}
+
+
+/* Methods */
+
+/*%
+ * void irp_close(struct irs_acc *this)
+ *
+ */
+
+static void
+irp_close(struct irs_acc *this) {
+ struct irp_p *irp = (struct irp_p *)this->private;
+
+ if (irp != NULL) {
+ irs_irp_disconnect(irp);
+ memput(irp, sizeof *irp);
+ }
+
+ memput(this, sizeof *this);
+}
+
+
+
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_ho.c b/usr/src/lib/libresolv2_joy/common/irs/irp_ho.c
new file mode 100644
index 0000000000..b0de31dc89
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_ho.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_ho.c,v 1.3 2005/04/27 04:56:28 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define Max(a,b) ((a) > (b) ? (a) : (b))
+
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct hostent host;
+};
+
+/* Forward. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+
+static void free_host(struct hostent *ho);
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+/* Public. */
+
+/*%
+ * struct irs_ho * irs_irp_ho(struct irs_acc *this)
+ *
+ * Notes:
+ *
+ * Initializes the irp_ho module.
+ *
+ */
+
+struct irs_ho *
+irs_irp_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ if (!(ho = memget(sizeof *ho))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x0, sizeof *ho);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ho, sizeof *ho);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->addrinfo = ho_addrinfo;
+
+ return (ho);
+}
+
+/* Methods. */
+
+/*%
+ * Closes down the module.
+ *
+ */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+
+ free_host(&pvt->host);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+
+
+/*
+ * struct hostent * ho_byname(struct irs_ho *this, const char *name)
+ *
+ */
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ return (ho_byname2(this, name, AF_INET));
+}
+
+
+
+
+
+/*
+ * struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af)
+ *
+ */
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (ho->h_name != NULL &&
+ strcmp(name, ho->h_name) == 0 &&
+ af == ho->h_addrtype) {
+ return (ho);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostbyname2 %s %s",
+ name, ADDR_T_STR(af)) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+
+
+/*
+ * struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ * int len, int af)
+ *
+ */
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char **p;
+ char paddr[MAXPADDRSIZE];
+ char text[256];
+
+ if (ho->h_name != NULL &&
+ af == ho->h_addrtype &&
+ len == ho->h_length) {
+ for (p = ho->h_addr_list ; *p != NULL ; p++) {
+ if (memcmp(*p, addr, len) == 0)
+ return (ho);
+ }
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (inet_ntop(af, addr, paddr, sizeof paddr) == NULL) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostbyaddr %s %s",
+ paddr, ADDR_T_STR(af)) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+/*%
+ * The implementation for gethostent(3). The first time it's
+ * called all the data is pulled from the remote(i.e. what
+ * the maximum number of gethostent(3) calls would return)
+ * and that data is cached.
+ *
+ */
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *ho = &pvt->host;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "gethostent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETHOST_OK) {
+ free_host(ho);
+ if (irp_unmarshall_ho(ho, body) != 0) {
+ ho = NULL;
+ }
+ } else {
+ ho = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (ho);
+}
+
+/*%
+ * void ho_rewind(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "sethostent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETHOST_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "sethostent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * void ho_minimize(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ free_host(&pvt->host);
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+/*%
+ * void free_host(struct hostent *ho)
+ *
+ */
+
+static void
+free_host(struct hostent *ho) {
+ char **p;
+
+ if (ho == NULL) {
+ return;
+ }
+
+ if (ho->h_name != NULL)
+ free(ho->h_name);
+
+ if (ho->h_aliases != NULL) {
+ for (p = ho->h_aliases ; *p != NULL ; p++)
+ free(*p);
+ free(ho->h_aliases);
+ }
+
+ if (ho->h_addr_list != NULL) {
+ for (p = ho->h_addr_list ; *p != NULL ; p++)
+ free(*p);
+ free(ho->h_addr_list);
+ }
+}
+
+/* dummy */
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ UNUSED(this);
+ UNUSED(name);
+ UNUSED(pai);
+ return(NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_ng.c b/usr/src/lib/libresolv2_joy/common/irs/irp_ng.c
new file mode 100644
index 0000000000..1af862cab4
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_ng.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irp_ng.c,v 1.4 2006/12/07 04:46:27 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+};
+
+
+/* Forward */
+
+static void ng_rewind(struct irs_ng *, const char*);
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **, const char **,
+ const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_minimize(struct irs_ng *);
+
+
+/* Public */
+
+/*%
+ * Intialize the irp netgroup module.
+ *
+ */
+
+struct irs_ng *
+irs_irp_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+
+
+/*
+ * void ng_close(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ng_minimize(this);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * void ng_rewind(struct irs_ng *this, const char *group)
+ *
+ *
+ */
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata,
+ "setnetgrent %s", group) != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETNETGR_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setnetgrent(%s) failed: %s",
+ group, text);
+ }
+ }
+
+ return;
+}
+
+/*
+ * Get the next netgroup item from the cache.
+ *
+ */
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ int code;
+ char *body = NULL;
+ size_t bodylen;
+ int rval = 0;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (0);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetgrent") != 0)
+ return (0);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (0);
+ }
+
+ if (code == IRPD_GETNETGR_OK) {
+ if (irp_unmarshall_ng(host, user, domain, body) == 0) {
+ rval = 1;
+ }
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (rval);
+}
+
+/*
+ * Search for a match in a netgroup.
+ *
+ */
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *host, const char *user, const char *domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *body = NULL;
+ size_t bodylen = 0;
+ int code;
+ char text[256];
+ int rval = 0;
+
+ UNUSED(name);
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (0);
+ }
+
+ if (irp_marshall_ng(host, user, domain, &body, &bodylen) != 0) {
+ return (0);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "innetgr %s", body) == 0) {
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code == IRPD_GETNETGR_MATCHES) {
+ rval = 1;
+ }
+ }
+
+ memput(body, bodylen);
+
+ return (rval);
+}
+
+
+
+
+/*
+ * void ng_minimize(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* Private */
+
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_nw.c b/usr/src/lib/libresolv2_joy/common/irs/irp_nw.c
new file mode 100644
index 0000000000..3f2381f95d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_nw.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_nw.c,v 1.4 2006/03/09 23:57:56 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#if 0
+
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct nwent net;
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+
+static void free_nw(struct nwent *nw);
+
+
+/* Public */
+
+/*%
+ * struct irs_nw * irs_irp_nw(struct irs_acc *this)
+ *
+ */
+
+struct irs_nw *
+irs_irp_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x0, sizeof *nw);
+ pvt->girpdata = this->private;
+
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ return (nw);
+}
+
+/* Methods */
+
+/*%
+ * void nw_close(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+
+ free_nw(&pvt->net);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * struct nwent * nw_byaddr(struct irs_nw *this, void *net,
+ * int length, int type)
+ *
+ */
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char paddr[24]; /*%< bigenough for ip4 w/ cidr spec. */
+ char text[256];
+
+ if (inet_net_ntop(type, net, length, paddr, sizeof paddr) == NULL) {
+ return (NULL);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetbyaddr %s %s",
+ paddr, ADDR_T_STR(type)) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (nw);
+}
+
+/*%
+ * struct nwent * nw_byname(struct irs_nw *this, const char *name, int type)
+ *
+ */
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (nw->n_name != NULL &&
+ strcmp(name, nw->n_name) == 0 &&
+ nw->n_addrtype == type) {
+ return (nw);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetbyname %s", name) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (nw);
+}
+
+/*%
+ * void nw_rewind(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setnetent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETNET_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setnetent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * Prepares the cache if necessary and returns the first, or
+ * next item from it.
+ */
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *nw = &pvt->net;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getnetent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETNET_OK) {
+ free_nw(nw);
+ if (irp_unmarshall_nw(nw, body) != 0) {
+ nw = NULL;
+ }
+ } else {
+ nw = NULL;
+ }
+
+ if (body != NULL)
+ memput(body, bodylen);
+ return (nw);
+}
+
+/*%
+ * void nw_minimize(struct irs_nw *this)
+ *
+ */
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* private. */
+
+/*%
+ * deallocate all the memory irp_unmarshall_pw allocated.
+ *
+ */
+
+static void
+free_nw(struct nwent *nw) {
+ char **p;
+
+ if (nw == NULL)
+ return;
+
+ if (nw->n_name != NULL)
+ free(nw->n_name);
+
+ if (nw->n_aliases != NULL) {
+ for (p = nw->n_aliases ; *p != NULL ; p++) {
+ free(*p);
+ }
+ free(nw->n_aliases);
+ }
+
+ if (nw->n_addr != NULL)
+ free(nw->n_addr);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_p.h b/usr/src/lib/libresolv2_joy/common/irs/irp_p.h
new file mode 100644
index 0000000000..4f943f81bd
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_p.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irp_p.h,v 1.5 2005/04/27 04:56:28 sra Exp $
+ */
+
+#ifndef _IRP_P_H_INCLUDED
+#define _IRP_P_H_INCLUDED
+
+#include <stdio.h>
+
+struct irp_p {
+ char inbuffer[1024];
+ int inlast; /*%< index of one past the last char in buffer */
+ int incurr; /*%< index of the next char to be read from buffer */
+ int fdCxn;
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_irp_acc __P((const char *));
+extern struct irs_gr * irs_irp_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_irp_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_irp_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_irp_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_irp_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_irp_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_irp_ng __P((struct irs_acc *));
+
+int irs_irp_connect(struct irp_p *pvt);
+int irs_irp_is_connected(struct irp_p *pvt);
+void irs_irp_disconnect(struct irp_p *pvt);
+int irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen);
+char *irs_irp_read_body(struct irp_p *pvt, size_t *size);
+int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+ char *text, size_t textlen,
+ char **body, size_t *bodylen);
+
+extern int irp_log_errors;
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_pr.c b/usr/src/lib/libresolv2_joy/common/irs/irp_pr.c
new file mode 100644
index 0000000000..ea876e8281
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_pr.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_pr.c,v 1.3 2005/04/27 04:56:29 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+#define MAXALIASES 35
+
+/* Types */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct protoent proto;
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+
+static void free_proto(struct protoent *pr);
+
+/* Public */
+
+/*%
+ * struct irs_pr * irs_irp_pr(struct irs_acc *this)
+ *
+ */
+
+struct irs_pr *
+irs_irp_pr(struct irs_acc *this) {
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pr, 0x0, sizeof *pr);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *pr);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ return (pr);
+}
+
+/* Methods */
+
+/*%
+ * void pr_close(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ pr_minimize(this);
+
+ free_proto(&pvt->proto);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * struct protoent * pr_byname(struct irs_pr *this, const char *name)
+ *
+ */
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ int i;
+ char text[256];
+
+ if (pr->p_name != NULL && strcmp(name, pr->p_name) == 0) {
+ return (pr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ i = irs_irp_send_command(pvt->girpdata, "getprotobyname %s", name);
+ if (i != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * struct protoent * pr_bynumber(struct irs_pr *this, int proto)
+ *
+ */
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body = NULL;
+ size_t bodylen;
+ int code;
+ int i;
+ char text[256];
+
+ if (pr->p_name != NULL && proto == pr->p_proto) {
+ return (pr);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ i = irs_irp_send_command(pvt->girpdata, "getprotobynumber %d", proto);
+ if (i != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * void pr_rewind(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setprotoent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETPROTO_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setprotoent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * Prepares the cache if necessary and returns the next item in it.
+ *
+ */
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct protoent *pr = &pvt->proto;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getprotoent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETPROTO_OK) {
+ free_proto(pr);
+ if (irp_unmarshall_pr(pr, body) != 0) {
+ pr = NULL;
+ }
+ } else {
+ pr = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (pr);
+}
+
+/*%
+ * void pr_minimize(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+/*%
+ * Deallocate all the memory irp_unmarshall_pr allocated.
+ *
+ */
+
+static void
+free_proto(struct protoent *pr) {
+ char **p;
+
+ if (pr == NULL)
+ return;
+
+ if (pr->p_name != NULL)
+ free(pr->p_name);
+
+ for (p = pr->p_aliases ; p != NULL && *p != NULL ; p++)
+ free(*p);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irp_sv.c b/usr/src/lib/libresolv2_joy/common/irs/irp_sv.c
new file mode 100644
index 0000000000..577e697fe6
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irp_sv.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irp_sv.c,v 1.3 2005/04/27 04:56:29 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Types */
+
+struct pvt {
+ struct irp_p *girpdata;
+ int warned;
+ struct servent service;
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+
+static void free_service(struct servent *sv);
+
+
+
+/* Public */
+
+/*%
+ * struct irs_sv * irs_irp_sv(struct irs_acc *this)
+ *
+ */
+
+struct irs_sv *
+irs_irp_sv(struct irs_acc *this) {
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ if ((sv = memget(sizeof *sv)) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x0, sizeof *sv);
+
+ if ((pvt = memget(sizeof *pvt)) == NULL) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pvt->girpdata = this->private;
+
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+
+ return (sv);
+}
+
+/* Methods */
+
+/*%
+ * void sv_close(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ sv_minimize(this);
+
+ free_service(&pvt->service);
+
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * Fills the cache if necessary and returns the next item from it.
+ *
+ */
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ size_t bodylen;
+ int code;
+ char text[256];
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservent") != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * struct servent * sv_byname(struct irs_sv *this, const char *name,
+ * const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ char text[256];
+ size_t bodylen;
+ int code;
+
+ if (sv->s_name != NULL &&
+ strcmp(name, sv->s_name) == 0 &&
+ strcasecmp(proto, sv->s_proto) == 0) {
+ return (sv);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservbyname %s %s",
+ name, proto) != 0)
+ return (NULL);
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * struct servent * sv_byport(struct irs_sv *this, int port,
+ * const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct servent *sv = &pvt->service;
+ char *body;
+ size_t bodylen;
+ char text[256];
+ int code;
+
+ if (sv->s_name != NULL &&
+ port == sv->s_port &&
+ strcasecmp(proto, sv->s_proto) == 0) {
+ return (sv);
+ }
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "getservbyport %d %s",
+ ntohs((short)port), proto) != 0) {
+ return (NULL);
+ }
+
+ if (irs_irp_get_full_response(pvt->girpdata, &code,
+ text, sizeof text,
+ &body, &bodylen) != 0) {
+ return (NULL);
+ }
+
+ if (code == IRPD_GETSERVICE_OK) {
+ free_service(sv);
+ if (irp_unmarshall_sv(sv, body) != 0) {
+ sv = NULL;
+ }
+ } else {
+ sv = NULL;
+ }
+
+ if (body != NULL) {
+ memput(body, bodylen);
+ }
+
+ return (sv);
+}
+
+/*%
+ * void sv_rewind(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char text[256];
+ int code;
+
+ if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+ return;
+ }
+
+ if (irs_irp_send_command(pvt->girpdata, "setservent") != 0) {
+ return;
+ }
+
+ code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+ if (code != IRPD_GETSERVICE_SETOK) {
+ if (irp_log_errors) {
+ syslog(LOG_WARNING, "setservent failed: %s", text);
+ }
+ }
+
+ return;
+}
+
+/*%
+ * void sv_minimize(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+
+
+static void
+free_service(struct servent *sv) {
+ char **p;
+
+ if (sv == NULL) {
+ return;
+ }
+
+ if (sv->s_name != NULL) {
+ free(sv->s_name);
+ }
+
+ for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) {
+ free(*p);
+ }
+
+ if (sv->s_proto != NULL) {
+ free(sv->s_proto);
+ }
+}
+
+
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irpmarshall.c b/usr/src/lib/libresolv2_joy/common/irs/irpmarshall.c
new file mode 100644
index 0000000000..85ffff1866
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irpmarshall.c
@@ -0,0 +1,2301 @@
+/*
+ * Copyright(c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irpmarshall.c,v 1.7 2006/03/09 23:57:56 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#if 0
+
+Check values are in approrpriate endian order.
+
+Double check memory allocations on unmarhsalling
+
+#endif
+
+
+/* Extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "port_after.h"
+
+
+#ifndef HAVE_STRNDUP
+static char *strndup(const char *str, size_t len);
+#endif
+
+static char **splitarray(const char *buffer, const char *buffend, char delim);
+static int joinarray(char * const * argv, char *buffer, char delim);
+static char *getfield(char **res, size_t reslen, char **buffer, char delim);
+static size_t joinlength(char * const *argv);
+static void free_array(char **argv, size_t entries);
+
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+ (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+
+static char COMMA = ',';
+
+static const char *COMMASTR = ",";
+static const char *COLONSTR = ":";
+
+
+
+/* See big comment at bottom of irpmarshall.h for description. */
+
+
+#ifdef WANT_IRS_PW
+/* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on sucess, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) {
+ size_t need = 1 ; /*%< for null byte */
+ char pwUid[24];
+ char pwGid[24];
+ char pwChange[24];
+ char pwExpire[24];
+ const char *pwClass;
+ const char *fieldsep = COLONSTR;
+
+ if (pw == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(pwUid, "%ld", (long)pw->pw_uid);
+ sprintf(pwGid, "%ld", (long)pw->pw_gid);
+
+#ifdef HAVE_PW_CHANGE
+ sprintf(pwChange, "%ld", (long)pw->pw_change);
+#else
+ pwChange[0] = '0';
+ pwChange[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_EXPIRE
+ sprintf(pwExpire, "%ld", (long)pw->pw_expire);
+#else
+ pwExpire[0] = '0';
+ pwExpire[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_CLASS
+ pwClass = pw->pw_class;
+#else
+ pwClass = "";
+#endif
+
+ need += strlen(pw->pw_name) + 1; /*%< one for fieldsep */
+ need += strlen(pw->pw_passwd) + 1;
+ need += strlen(pwUid) + 1;
+ need += strlen(pwGid) + 1;
+ need += strlen(pwClass) + 1;
+ need += strlen(pwChange) + 1;
+ need += strlen(pwExpire) + 1;
+ need += strlen(pw->pw_gecos) + 1;
+ need += strlen(pw->pw_dir) + 1;
+ need += strlen(pw->pw_shell) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, pw->pw_name); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_passwd); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwUid); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwGid); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwClass); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwChange); strcat(*buffer, fieldsep);
+ strcat(*buffer, pwExpire); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_gecos); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_dir); strcat(*buffer, fieldsep);
+ strcat(*buffer, pw->pw_shell); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_pw(struct passwd *pw, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ *
+ */
+
+int
+irp_unmarshall_pw(struct passwd *pw, char *buffer) {
+ char *name, *pass, *class, *gecos, *dir, *shell;
+ uid_t pwuid;
+ gid_t pwgid;
+ time_t pwchange;
+ time_t pwexpire;
+ char *p;
+ long t;
+ char tmpbuf[24];
+ char *tb = &tmpbuf[0];
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ name = pass = class = gecos = dir = shell = NULL;
+ p = buffer;
+
+ /* pw_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+ goto error;
+ }
+
+ /* pw_passwd field */
+ pass = NULL;
+ if (getfield(&pass, 0, &p, fieldsep) == NULL) { /*%< field can be empty */
+ goto error;
+ }
+
+
+ /* pw_uid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwuid = (uid_t)t;
+ if ((long) pwuid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_gid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwgid = (gid_t)t;
+ if ((long)pwgid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_class field */
+ class = NULL;
+ if (getfield(&class, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_change field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwchange = (time_t)t;
+ if ((long)pwchange != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_expire field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ pwexpire = (time_t)t;
+ if ((long) pwexpire != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+
+ /* pw_gecos field */
+ gecos = NULL;
+ if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_dir field */
+ dir = NULL;
+ if (getfield(&dir, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ /* pw_shell field */
+ shell = NULL;
+ if (getfield(&shell, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+
+ pw->pw_name = name;
+ pw->pw_passwd = pass;
+ pw->pw_uid = pwuid;
+ pw->pw_gid = pwgid;
+ pw->pw_gecos = gecos;
+ pw->pw_dir = dir;
+ pw->pw_shell = shell;
+
+#ifdef HAVE_PW_CHANGE
+ pw->pw_change = pwchange;
+#endif
+#ifdef HAVE_PW_CLASS
+ pw->pw_class = class;
+#endif
+#ifdef HAVE_PW_EXPIRE
+ pw->pw_expire = pwexpire;
+#endif
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (pass != NULL) free(pass);
+ if (gecos != NULL) free(gecos);
+ if (dir != NULL) free(dir);
+ if (shell != NULL) free(shell);
+
+ return (-1);
+}
+
+/* ------------------------- struct passwd ------------------------- */
+#endif /* WANT_IRS_PW */
+/* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ */
+
+int
+irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char grGid[24];
+ const char *fieldsep = COLONSTR;
+
+ if (gr == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(grGid, "%ld", (long)gr->gr_gid);
+
+ need += strlen(gr->gr_name) + 1;
+#ifndef MISSING_GR_PASSWD
+ need += strlen(gr->gr_passwd) + 1;
+#else
+ need++;
+#endif
+ need += strlen(grGid) + 1;
+ need += joinlength(gr->gr_mem) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, gr->gr_name); strcat(*buffer, fieldsep);
+#ifndef MISSING_GR_PASSWD
+ strcat(*buffer, gr->gr_passwd);
+#endif
+ strcat(*buffer, fieldsep);
+ strcat(*buffer, grGid); strcat(*buffer, fieldsep);
+ joinarray(gr->gr_mem, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_gr(struct group *gr, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_gr(struct group *gr, char *buffer) {
+ char *p, *q;
+ gid_t grgid;
+ long t;
+ char *name = NULL;
+ char *pass = NULL;
+ char **members = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (gr == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* gr_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* gr_passwd field */
+ pass = NULL;
+ if (getfield(&pass, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+
+ /* gr_gid field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ grgid = (gid_t)t;
+ if ((long) grgid != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+ /* gr_mem field. Member names are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ members = splitarray(p, q, COMMA);
+ if (members == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ gr->gr_name = name;
+#ifndef MISSING_GR_PASSWD
+ gr->gr_passwd = pass;
+#endif
+ gr->gr_gid = grgid;
+ gr->gr_mem = members;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (pass != NULL) free(pass);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct group ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char svPort[24];
+ const char *fieldsep = COLONSTR;
+ short realport;
+
+ if (sv == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* the int s_port field is actually a short in network order. We
+ want host order to make the marshalled data look correct */
+ realport = ntohs((short)sv->s_port);
+ sprintf(svPort, "%d", realport);
+
+ need += strlen(sv->s_name) + 1;
+ need += joinlength(sv->s_aliases) + 1;
+ need += strlen(svPort) + 1;
+ need += strlen(sv->s_proto) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, sv->s_name); strcat(*buffer, fieldsep);
+ joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, svPort); strcat(*buffer, fieldsep);
+ strcat(*buffer, sv->s_proto); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_sv(struct servent *sv, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_sv(struct servent *sv, char *buffer) {
+ char *p, *q;
+ short svport;
+ long t;
+ char *name = NULL;
+ char *proto = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (sv == NULL || buffer == NULL)
+ return (-1);
+
+ p = buffer;
+
+
+ /* s_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* s_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* s_port field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ svport = (short)t;
+ if ((long) svport != t) { /*%< value must have been too big. */
+ goto error;
+ }
+ svport = htons(svport);
+
+ /* s_proto field */
+ proto = NULL;
+ if (getfield(&proto, 0, &p, fieldsep) == NULL) {
+ goto error;
+ }
+
+ sv->s_name = name;
+ sv->s_aliases = aliases;
+ sv->s_port = svport;
+ sv->s_proto = proto;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ if (proto != NULL) free(proto);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct servent ------------------------- */
+
+/* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char prProto[24];
+ const char *fieldsep = COLONSTR;
+
+ if (pr == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(prProto, "%d", (int)pr->p_proto);
+
+ need += strlen(pr->p_name) + 1;
+ need += joinlength(pr->p_aliases) + 1;
+ need += strlen(prProto) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, pr->p_name); strcat(*buffer, fieldsep);
+ joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, prProto); strcat(*buffer, fieldsep);
+
+ return (0);
+
+}
+
+/*%
+ * int irp_unmarshall_pr(struct protoent *pr, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure
+ *
+ */
+
+int irp_unmarshall_pr(struct protoent *pr, char *buffer) {
+ char *p, *q;
+ int prproto;
+ long t;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (pr == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* p_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* p_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* p_proto field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ prproto = (int)t;
+ if ((long) prproto != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+ pr->p_name = name;
+ pr->p_aliases = aliases;
+ pr->p_proto = prproto;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+/* ------------------------- struct protoent ------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char hoaddrtype[24];
+ char holength[24];
+ char **av;
+ char *p;
+ int addrlen;
+ int malloced = 0;
+ size_t remlen;
+ const char *fieldsep = "@";
+
+ if (ho == NULL || len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch(ho->h_addrtype) {
+ case AF_INET:
+ strcpy(hoaddrtype, "AF_INET");
+ break;
+
+ case AF_INET6:
+ strcpy(hoaddrtype, "AF_INET6");
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sprintf(holength, "%d", ho->h_length);
+
+ need += strlen(ho->h_name) + 1;
+ need += joinlength(ho->h_aliases) + 1;
+ need += strlen(hoaddrtype) + 1;
+ need += strlen(holength) + 1;
+
+ /* we determine an upper bound on the string length needed, not an
+ exact length. */
+ addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /*%< XX other AF's?? */
+ for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
+ need += addrlen;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ malloced = 1;
+ }
+
+ strcpy(*buffer, ho->h_name); strcat(*buffer, fieldsep);
+ joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+ strcat(*buffer, hoaddrtype); strcat(*buffer, fieldsep);
+ strcat(*buffer, holength); strcat(*buffer, fieldsep);
+
+ p = *buffer + strlen(*buffer);
+ remlen = need - strlen(*buffer);
+ for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) {
+ if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) {
+ goto error;
+ }
+ if (*(av + 1) != NULL)
+ strcat(p, COMMASTR);
+ remlen -= strlen(p);
+ p += strlen(p);
+ }
+ strcat(*buffer, fieldsep);
+
+ return (0);
+
+ error:
+ if (malloced) {
+ memput(*buffer, need);
+ }
+
+ return (-1);
+}
+
+/*%
+ * int irp_unmarshall_ho(struct hostent *ho, char *buffer)
+ *
+ * notes: \li
+ *
+ * See irpmarshall.h.
+ *
+ * return: \li
+ *
+ * 0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ho(struct hostent *ho, char *buffer) {
+ char *p, *q, *r;
+ int hoaddrtype;
+ int holength;
+ long t;
+ char *name;
+ char **aliases = NULL;
+ char **hohaddrlist = NULL;
+ size_t hoaddrsize;
+ char tmpbuf[24];
+ char *tb;
+ char **alist;
+ int addrcount;
+ char fieldsep = '@';
+ int myerrno = EINVAL;
+
+ if (ho == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ p = buffer;
+
+ /* h_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* h_aliases field */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ hoaddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ hoaddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* h_length field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ t = strtol(tmpbuf, &tb, 10);
+ if (*tb) {
+ goto error; /*%< junk in value */
+ }
+ holength = (int)t;
+ if ((long) holength != t) { /*%< value must have been too big. */
+ goto error;
+ }
+
+
+ /* h_addr_list field */
+ q = strchr(p, fieldsep);
+ if (q == NULL)
+ goto error;
+
+ /* count how many addresss are in there */
+ if (q > p + 1) {
+ for (addrcount = 1, r = p ; r != q ; r++) {
+ if (*r == COMMA)
+ addrcount++;
+ }
+ } else {
+ addrcount = 0;
+ }
+
+ hoaddrsize = (addrcount + 1) * sizeof (char *);
+ hohaddrlist = malloc(hoaddrsize);
+ if (hohaddrlist == NULL) {
+ myerrno = ENOMEM;
+ goto error;
+ }
+
+ memset(hohaddrlist, 0x0, hoaddrsize);
+
+ alist = hohaddrlist;
+ for (t = 0, r = p ; r != q ; p = r + 1, t++) {
+ char saved;
+ while (r != q && *r != COMMA) r++;
+ saved = *r;
+ *r = 0x0;
+
+ alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16);
+ if (alist[t] == NULL) {
+ myerrno = ENOMEM;
+ goto error;
+ }
+
+ if (inet_pton(hoaddrtype, p, alist[t]) == -1)
+ goto error;
+ *r = saved;
+ }
+ alist[t] = NULL;
+
+ ho->h_name = name;
+ ho->h_aliases = aliases;
+ ho->h_addrtype = hoaddrtype;
+ ho->h_length = holength;
+ ho->h_addr_list = hohaddrlist;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(hohaddrlist, 0);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+/* ------------------------- struct hostent------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ng(const char *host, const char *user,
+ * const char *domain, char *buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See note for irp_marshall_ng_start
+ *
+ * return: \li
+ *
+ * 0 on success, 0 on failure.
+ *
+ */
+
+int
+irp_marshall_ng(const char *host, const char *user, const char *domain,
+ char **buffer, size_t *len) {
+ size_t need = 1; /*%< for nul byte */
+ const char *fieldsep = ",";
+
+ if (len == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ need += 4; /*%< two parens and two commas */
+ need += (host == NULL ? 0 : strlen(host));
+ need += (user == NULL ? 0 : strlen(user));
+ need += (domain == NULL ? 0 : strlen(domain));
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ } else if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ (*buffer)[0] = '(';
+ (*buffer)[1] = '\0';
+
+ if (host != NULL)
+ strcat(*buffer, host);
+ strcat(*buffer, fieldsep);
+
+ if (user != NULL)
+ strcat(*buffer, user);
+ strcat(*buffer, fieldsep);
+
+ if (domain != NULL)
+ strcat(*buffer, domain);
+ strcat(*buffer, ")");
+
+ return (0);
+}
+
+
+
+/* ---------- */
+
+/*%
+ * int irp_unmarshall_ng(const char **host, const char **user,
+ * const char **domain, char *buffer)
+ *
+ * notes: \li
+ *
+ * Unpacks the BUFFER into 3 character arrays it allocates and assigns
+ * to *HOST, *USER and *DOMAIN. If any field of the value is empty,
+ * then the corresponding paramater value will be set to NULL.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ */
+
+int
+irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp,
+ char *buffer)
+{
+ char *p, *q;
+ char fieldsep = ',';
+ int myerrno = EINVAL;
+ char *host, *user, *domain;
+
+ if (userp == NULL || hostp == NULL ||
+ domainp == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ host = user = domain = NULL;
+
+ p = buffer;
+ while (isspace((unsigned char)*p)) {
+ p++;
+ }
+ if (*p != '(') {
+ goto error;
+ }
+
+ q = p + 1;
+ while (*q && *q != fieldsep)
+ q++;
+ if (!*q) {
+ goto error;
+ } else if (q > p + 1) {
+ host = strndup(p, q - p);
+ }
+
+ p = q + 1;
+ if (!*p) {
+ goto error;
+ } else if (*p != fieldsep) {
+ q = p + 1;
+ while (*q && *q != fieldsep)
+ q++;
+ if (!*q) {
+ goto error;
+ }
+ user = strndup(p, q - p);
+ } else {
+ p++;
+ }
+
+ if (!*p) {
+ goto error;
+ } else if (*p != ')') {
+ q = p + 1;
+ while (*q && *q != ')')
+ q++;
+ if (!*q) {
+ goto error;
+ }
+ domain = strndup(p, q - p);
+ }
+ *hostp = host;
+ *userp = user;
+ *domainp = domain;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (host != NULL) free(host);
+ if (user != NULL) free(user);
+
+ return (-1);
+}
+
+/* ------------------------- struct netgrp ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See at top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char nAddrType[24];
+ char nNet[MAXPADDRSIZE];
+ const char *fieldsep = COLONSTR;
+
+ if (ne == NULL || len == NULL) {
+ return (-1);
+ }
+
+ strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+ if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length,
+ nNet, sizeof nNet) == NULL) {
+ return (-1);
+ }
+
+
+ need += strlen(ne->n_name) + 1;
+ need += joinlength(ne->n_aliases) + 1;
+ need += strlen(nAddrType) + 1;
+ need += strlen(nNet) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep);
+ joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+ strcat(*buffer, nAddrType); strcat(*buffer, fieldsep);
+ strcat(*buffer, nNet); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_nw(struct nwent *ne, char *buffer)
+ *
+ * notes: \li
+ *
+ * See note up top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_nw(struct nwent *ne, char *buffer) {
+ char *p, *q;
+ int naddrtype;
+ long nnet;
+ int bits;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (ne == NULL || buffer == NULL) {
+ goto error;
+ }
+
+ p = buffer;
+
+ /* n_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* n_aliases field. Aliases are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ naddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ naddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* n_net field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ nnet = 0;
+ bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+ if (bits < 0) {
+ goto error;
+ }
+
+ /* nnet = ntohl(nnet); */ /* keep in network order for nwent */
+
+ ne->n_name = name;
+ ne->n_aliases = aliases;
+ ne->n_addrtype = naddrtype;
+ ne->n_length = bits;
+ ne->n_addr = malloc(sizeof nnet);
+ if (ne->n_addr == NULL) {
+ goto error;
+ }
+
+ memcpy(ne->n_addr, &nnet, sizeof nnet);
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct nwent ------------------------- */
+
+
+/* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */
+
+/*%
+ * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len)
+ *
+ * notes: \li
+ *
+ * See at top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) {
+ size_t need = 1; /*%< for null byte */
+ char nAddrType[24];
+ char nNet[MAXPADDRSIZE];
+ const char *fieldsep = COLONSTR;
+ long nval;
+
+ if (ne == NULL || len == NULL) {
+ return (-1);
+ }
+
+ strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+ nval = htonl(ne->n_net);
+ if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) {
+ return (-1);
+ }
+
+ need += strlen(ne->n_name) + 1;
+ need += joinlength(ne->n_aliases) + 1;
+ need += strlen(nAddrType) + 1;
+ need += strlen(nNet) + 1;
+
+ if (buffer == NULL) {
+ *len = need;
+ return (0);
+ }
+
+ if (*buffer != NULL && need > *len) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*buffer == NULL) {
+ need += 2; /*%< for CRLF */
+ *buffer = memget(need);
+ if (*buffer == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ *len = need;
+ }
+
+ strcpy(*buffer, ne->n_name); strcat(*buffer, fieldsep);
+ joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+ strcat(*buffer, nAddrType); strcat(*buffer, fieldsep);
+ strcat(*buffer, nNet); strcat(*buffer, fieldsep);
+
+ return (0);
+}
+
+/*%
+ * int irp_unmarshall_ne(struct netent *ne, char *buffer)
+ *
+ * notes: \li
+ *
+ * See note up top.
+ *
+ * return: \li
+ *
+ * 0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ne(struct netent *ne, char *buffer) {
+ char *p, *q;
+ int naddrtype;
+ long nnet;
+ int bits;
+ char *name = NULL;
+ char **aliases = NULL;
+ char tmpbuf[24];
+ char *tb;
+ char fieldsep = ':';
+ int myerrno = EINVAL;
+
+ if (ne == NULL || buffer == NULL) {
+ goto error;
+ }
+
+ p = buffer;
+
+ /* n_name field */
+ name = NULL;
+ if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0U) {
+ goto error;
+ }
+
+
+ /* n_aliases field. Aliases are separated by commas */
+ q = strchr(p, fieldsep);
+ if (q == NULL) {
+ goto error;
+ }
+ aliases = splitarray(p, q, COMMA);
+ if (aliases == NULL) {
+ myerrno = errno;
+ goto error;
+ }
+ p = q + 1;
+
+
+ /* h_addrtype field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ if (strcmp(tmpbuf, "AF_INET") == 0)
+ naddrtype = AF_INET;
+ else if (strcmp(tmpbuf, "AF_INET6") == 0)
+ naddrtype = AF_INET6;
+ else
+ goto error;
+
+
+ /* n_net field */
+ tb = tmpbuf;
+ if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+ strlen(tb) == 0U) {
+ goto error;
+ }
+ bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+ if (bits < 0) {
+ goto error;
+ }
+ nnet = ntohl(nnet);
+
+ ne->n_name = name;
+ ne->n_aliases = aliases;
+ ne->n_addrtype = naddrtype;
+ ne->n_net = nnet;
+
+ return (0);
+
+ error:
+ errno = myerrno;
+
+ if (name != NULL) free(name);
+ free_array(aliases, 0);
+
+ return (-1);
+}
+
+
+/* ------------------------- struct netent ------------------------- */
+
+
+/* =========================================================================== */
+
+/*%
+ * static char ** splitarray(const char *buffer, const char *buffend, char delim)
+ *
+ * notes: \li
+ *
+ * Split a delim separated astring. Not allowed
+ * to have two delims next to each other. BUFFER points to begining of
+ * string, BUFFEND points to one past the end of the string
+ * (i.e. points at where the null byte would be if null
+ * terminated).
+ *
+ * return: \li
+ *
+ * Returns a malloced array of pointers, each pointer pointing to a
+ * malloced string. If BUFEER is an empty string, then return values is
+ * array of 1 pointer that is NULL. Returns NULL on failure.
+ *
+ */
+
+static char **
+splitarray(const char *buffer, const char *buffend, char delim) {
+ const char *p, *q;
+ int count = 0;
+ char **arr = NULL;
+ char **aptr;
+
+ if (buffend < buffer)
+ return (NULL);
+ else if (buffend > buffer && *buffer == delim)
+ return (NULL);
+ else if (buffend > buffer && *(buffend - 1) == delim)
+ return (NULL);
+
+ /* count the number of field and make sure none are empty */
+ if (buffend > buffer + 1) {
+ for (count = 1, q = buffer ; q != buffend ; q++) {
+ if (*q == delim) {
+ if (q > buffer && (*(q - 1) == delim)) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ count++;
+ }
+ }
+ }
+
+ if (count > 0) {
+ count++ ; /*%< for NULL at end */
+ aptr = arr = malloc(count * sizeof (char *));
+ if (aptr == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ memset(arr, 0x0, count * sizeof (char *));
+ for (p = buffer ; p < buffend ; p++) {
+ for (q = p ; *q != delim && q != buffend ; q++)
+ /* nothing */;
+ *aptr = strndup(p, q - p);
+
+ p = q;
+ aptr++;
+ }
+ *aptr = NULL;
+ } else {
+ arr = malloc(sizeof (char *));
+ if (arr == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ *arr = NULL;
+ }
+
+ return (arr);
+}
+
+/*%
+ * static size_t joinlength(char * const *argv)
+ *
+ * return: \li
+ *
+ * the number of bytes in all the arrays pointed at
+ * by argv, including their null bytes(which will usually be turned
+ * into commas).
+ *
+ *
+ */
+
+static size_t
+joinlength(char * const *argv) {
+ int len = 0;
+
+ while (argv && *argv) {
+ len += (strlen(*argv) + 1);
+ argv++;
+ }
+
+ return (len);
+}
+
+/*%
+ * int joinarray(char * const *argv, char *buffer, char delim)
+ *
+ * notes: \li
+ *
+ * Copy all the ARGV strings into the end of BUFFER
+ * separating them with DELIM. BUFFER is assumed to have
+ * enough space to hold everything and to be already null-terminated.
+ *
+ * return: \li
+ *
+ * 0 unless argv or buffer is NULL.
+ *
+ *
+ */
+
+static int
+joinarray(char * const *argv, char *buffer, char delim) {
+ char * const *p;
+ char sep[2];
+
+ if (argv == NULL || buffer == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sep[0] = delim;
+ sep[1] = 0x0;
+
+ for (p = argv ; *p != NULL ; p++) {
+ strcat(buffer, *p);
+ if (*(p + 1) != NULL) {
+ strcat(buffer, sep);
+ }
+ }
+
+ return (0);
+}
+
+/*%
+ * static char * getfield(char **res, size_t reslen, char **ptr, char delim)
+ *
+ * notes: \li
+ *
+ * Stores in *RES, which is a buffer of length RESLEN, a
+ * copy of the bytes from *PTR up to and including the first
+ * instance of DELIM. If *RES is NULL, then it will be
+ * assigned a malloced buffer to hold the copy. *PTR is
+ * modified to point at the found delimiter.
+ *
+ * return: \li
+ *
+ * If there was no delimiter, then NULL is returned,
+ * otherewise *RES is returned.
+ *
+ */
+
+static char *
+getfield(char **res, size_t reslen, char **ptr, char delim) {
+ char *q;
+
+ if (res == NULL || ptr == NULL || *ptr == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ q = strchr(*ptr, delim);
+
+ if (q == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ } else {
+ if (*res == NULL) {
+ *res = strndup(*ptr, q - *ptr);
+ } else {
+ if ((size_t)(q - *ptr + 1) > reslen) { /*%< to big for res */
+ errno = EINVAL;
+ return (NULL);
+ } else {
+ strncpy(*res, *ptr, q - *ptr);
+ (*res)[q - *ptr] = 0x0;
+ }
+ }
+ *ptr = q + 1;
+ }
+
+ return (*res);
+}
+
+
+
+
+
+#ifndef HAVE_STRNDUP
+/*
+ * static char * strndup(const char *str, size_t len)
+ *
+ * notes: \li
+ *
+ * like strdup, except do len bytes instead of the whole string. Always
+ * null-terminates.
+ *
+ * return: \li
+ *
+ * The newly malloced string.
+ *
+ */
+
+static char *
+strndup(const char *str, size_t len) {
+ char *p = malloc(len + 1);
+
+ if (p == NULL)
+ return (NULL);
+ strncpy(p, str, len);
+ p[len] = 0x0;
+ return (p);
+}
+#endif
+
+#if WANT_MAIN
+
+/*%
+ * static int strcmp_nws(const char *a, const char *b)
+ *
+ * notes: \li
+ *
+ * do a strcmp, except uneven lengths of whitespace compare the same
+ *
+ * return: \li
+ *
+ */
+
+static int
+strcmp_nws(const char *a, const char *b) {
+ while (*a && *b) {
+ if (isspace(*a) && isspace(*b)) {
+ do {
+ a++;
+ } while (isspace(*a));
+ do {
+ b++;
+ } while (isspace(*b));
+ }
+ if (*a < *b)
+ return (-1);
+ else if (*a > *b)
+ return (1);
+
+ a++;
+ b++;;
+ }
+
+ if (*a == *b)
+ return (0);
+ else if (*a > *b)
+ return (1);
+ else
+ return (-1);
+}
+
+#endif
+
+/*%
+ * static void free_array(char **argv, size_t entries)
+ *
+ * notes: \li
+ *
+ * Free argv and each of the pointers inside it. The end of
+ * the array is when a NULL pointer is found inside. If
+ * entries is > 0, then NULL pointers inside the array do
+ * not indicate the end of the array.
+ *
+ */
+
+static void
+free_array(char **argv, size_t entries) {
+ char **p = argv;
+ int useEntries = (entries > 0U);
+
+ if (argv == NULL)
+ return;
+
+ while ((useEntries && entries > 0U) || *p) {
+ if (*p)
+ free(*p);
+ p++;
+ if (useEntries)
+ entries--;
+ }
+ free(argv);
+}
+
+
+
+
+
+/* ************************************************** */
+
+#if WANT_MAIN
+
+/*% takes an option to indicate what sort of marshalling(read the code) and
+ an argument. If the argument looks like a marshalled buffer(has a ':'
+ embedded) then it's unmarshalled and the remarshalled and the new string
+ is compared to the old one.
+*/
+
+int
+main(int argc, char **argv) {
+ char buffer[1024];
+ char *b = &buffer[0];
+ size_t len = sizeof buffer;
+ char option;
+
+ if (argc < 2 || argv[1][0] != '-')
+ exit(1);
+
+ option = argv[1][1];
+ argv++;
+ argc--;
+
+
+#if 0
+ {
+ char buff[10];
+ char *p = argv[1], *q = &buff[0];
+
+ while (getfield(&q, sizeof buff, &p, ':') != NULL) {
+ printf("field: \"%s\"\n", q);
+ p++;
+ }
+ printf("p is now \"%s\"\n", p);
+ }
+#endif
+
+#if 0
+ {
+ char **x = splitarray(argv[1], argv[1] + strlen(argv[1]),
+ argv[2][0]);
+ char **p;
+
+ if (x == NULL)
+ printf("split failed\n");
+
+ for (p = x ; p != NULL && *p != NULL ; p++) {
+ printf("\"%s\"\n", *p);
+ }
+ }
+#endif
+
+#if 1
+ switch(option) {
+ case 'n': {
+ struct nwent ne;
+ int i;
+
+ if (strchr(argv[1], ':') != NULL) {
+ if (irp_unmarshall_nw(&ne, argv[1]) != 0) {
+ printf("Unmarhsalling failed\n");
+ exit(1);
+ }
+
+ printf("Name: \"%s\"\n", ne.n_name);
+ printf("Aliases:");
+ for (i = 0 ; ne.n_aliases[i] != NULL ; i++)
+ printf("\n\t\"%s\"", ne.n_aliases[i]);
+ printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype));
+ inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+ buffer, sizeof buffer);
+ printf("Net: \"%s\"\n", buffer);
+ *((long*)ne.n_addr) = htonl(*((long*)ne.n_addr));
+ inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+ buffer, sizeof buffer);
+ printf("Corrected Net: \"%s\"\n", buffer);
+ } else {
+ struct netent *np1 = getnetbyname(argv[1]);
+ ne.n_name = np1->n_name;
+ ne.n_aliases = np1->n_aliases;
+ ne.n_addrtype = np1->n_addrtype;
+ ne.n_addr = &np1->n_net;
+ ne.n_length = (IN_CLASSA(np1->n_net) ?
+ 8 :
+ (IN_CLASSB(np1->n_net) ?
+ 16 :
+ (IN_CLASSC(np1->n_net) ?
+ 24 : -1)));
+ np1->n_net = htonl(np1->n_net);
+ if (irp_marshall_nw(&ne, &b, &len) != 0) {
+ printf("Marshalling failed\n");
+ }
+ printf("%s\n", b);
+ }
+ break;
+ }
+
+
+ case 'r': {
+ char **hosts, **users, **domains;
+ size_t entries;
+ int i;
+ char *buff;
+ size_t size;
+ char *ngname;
+
+ if (strchr(argv[1], '(') != NULL) {
+ if (irp_unmarshall_ng(&ngname, &entries,
+ &hosts, &users, &domains,
+ argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+#define STRVAL(x) (x == NULL ? "*" : x)
+
+ printf("%s {\n", ngname);
+ for (i = 0 ; i < entries ; i++)
+ printf("\t\"%s\" : \"%s\" : \"%s\"\n",
+ STRVAL(hosts[i]),
+ STRVAL(users[i]),
+ STRVAL(domains[i]));
+ printf("}\n\n\n");
+
+
+ irp_marshall_ng_start(ngname, NULL, &size);
+ for (i = 0 ; i < entries ; i++)
+ irp_marshall_ng_next(hosts[i], users[i],
+ domains[i], NULL, &size);
+ irp_marshall_ng_end(NULL, &size);
+
+ buff = malloc(size);
+
+ irp_marshall_ng_start(ngname, buff, &size);
+ for (i = 0 ; i < entries ; i++) {
+ if (irp_marshall_ng_next(hosts[i], users[i],
+ domains[i], buff,
+ &size) != 0)
+ printf("next marshalling failed.\n");
+ }
+ irp_marshall_ng_end(buff, &size);
+
+ if (strcmp_nws(argv[1], buff) != 0) {
+ printf("compare failed:\n\t%s\n\t%s\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ char *h, *u, *d, *buff;
+ size_t size;
+
+ /* run through two times. First to figure out how
+ much of a buffer we need. Second to do the
+ actual marshalling */
+
+ setnetgrent(argv[1]);
+ irp_marshall_ng_start(argv[1], NULL, &size);
+ while (getnetgrent(&h, &u, &d) == 1)
+ irp_marshall_ng_next(h, u, d, NULL, &size);
+ irp_marshall_ng_end(NULL, &size);
+ endnetgrent(argv[1]);
+
+ buff = malloc(size);
+
+ setnetgrent(argv[1]);
+ if (irp_marshall_ng_start(argv[1], buff, &size) != 0)
+ printf("Marshalling start failed\n");
+
+ while (getnetgrent(&h, &u, &d) == 1) {
+ if (irp_marshall_ng_next(h, u, d, buff, &size)
+ != 0) {
+ printf("Marshalling failed\n");
+ }
+ }
+
+ irp_marshall_ng_end(buff, &size);
+ endnetgrent();
+
+ printf("success: %s\n", buff);
+ }
+ break;
+ }
+
+
+
+ case 'h': {
+ struct hostent he, *hp;
+ int i;
+
+
+ if (strchr(argv[1], '@') != NULL) {
+ if (irp_unmarshall_ho(&he, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+ printf("Host: \"%s\"\nAliases:", he.h_name);
+ for (i = 0 ; he.h_aliases[i] != NULL ; i++)
+ printf("\n\t\t\"%s\"", he.h_aliases[i]);
+ printf("\nAddr Type: \"%s\"\n",
+ ADDR_T_STR(he.h_addrtype));
+ printf("Length: %d\nAddresses:", he.h_length);
+ for (i = 0 ; he.h_addr_list[i] != 0 ; i++) {
+ inet_ntop(he.h_addrtype, he.h_addr_list[i],
+ buffer, sizeof buffer);
+ printf("\n\t\"%s\"\n", buffer);
+ }
+ printf("\n\n");
+
+ irp_marshall_ho(&he, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((hp = gethostbyname(argv[1])) == NULL) {
+ perror("gethostbyname");
+ printf("\"%s\"\n", argv[1]);
+ exit(1);
+ }
+
+ if (irp_marshall_ho(hp, &b, &len) != 0) {
+ printf("irp_marshall_ho failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+
+ case 's': {
+ struct servent *sv;
+ struct servent sv1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ sv = &sv1;
+ memset(sv, 0xef, sizeof (struct servent));
+ if (irp_unmarshall_sv(sv, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+
+ }
+
+ irp_marshall_sv(sv, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((sv = getservbyname(argv[1], argv[2])) == NULL) {
+ perror("getservent");
+ exit(1);
+ }
+
+ if (irp_marshall_sv(sv, &b, &len) != 0) {
+ printf("irp_marshall_sv failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+ case 'g': {
+ struct group *gr;
+ struct group gr1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ gr = &gr1;
+ memset(gr, 0xef, sizeof (struct group));
+ if (irp_unmarshall_gr(gr, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+
+ }
+
+ irp_marshall_gr(gr, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((gr = getgrnam(argv[1])) == NULL) {
+ perror("getgrnam");
+ exit(1);
+ }
+
+ if (irp_marshall_gr(gr, &b, &len) != 0) {
+ printf("irp_marshall_gr failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+
+ case 'p': {
+ struct passwd *pw;
+ struct passwd pw1;
+
+ if (strchr(argv[1], ':') != NULL) {
+ pw = &pw1;
+ memset(pw, 0xef, sizeof (*pw));
+ if (irp_unmarshall_pw(pw, argv[1]) != 0) {
+ printf("unmarshall failed\n");
+ exit(1);
+ }
+
+ printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n",
+ pw->pw_name, pw->pw_passwd, (long)pw->pw_uid,
+ (long)pw->pw_gid);
+ printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n",
+ pw->pw_class, (long)pw->pw_change, pw->pw_gecos);
+ printf("Shell: \"%s\"\nDirectory: \"%s\"\n",
+ pw->pw_shell, pw->pw_dir);
+
+ pw = getpwnam(pw->pw_name);
+ irp_marshall_pw(pw, &b, &len);
+ if (strcmp(argv[1], buffer) != 0) {
+ printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+ buffer, argv[1]);
+ } else {
+ printf("compare ok\n");
+ }
+ } else {
+ if ((pw = getpwnam(argv[1])) == NULL) {
+ perror("getpwnam");
+ exit(1);
+ }
+
+ if (irp_marshall_pw(pw, &b, &len) != 0) {
+ printf("irp_marshall_pw failed\n");
+ exit(1);
+ }
+
+ printf("success: \"%s\"\n", buffer);
+ }
+ break;
+ }
+
+ default:
+ printf("Wrong option: %c\n", option);
+ break;
+ }
+
+#endif
+
+ return (0);
+}
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irs_data.c b/usr/src/lib/libresolv2_joy/common/irs/irs_data.c
new file mode 100644
index 0000000000..f12ca20f38
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irs_data.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irs_data.c,v 1.12 2007/08/27 03:32:26 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#ifndef __BIND_NOSTATIC
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+#include <isc/memcluster.h>
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <irs.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+#undef _res
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#undef h_errno
+extern int h_errno;
+#endif
+
+extern struct __res_state _res;
+
+#ifdef DO_PTHREADS
+static pthread_key_t key;
+static int once = 0;
+#else
+static struct net_data *net_data;
+#endif
+
+void
+irs_destroy(void) {
+#ifndef DO_PTHREADS
+ if (net_data != NULL)
+ net_data_destroy(net_data);
+ net_data = NULL;
+#endif
+}
+
+void
+net_data_destroy(void *p) {
+ struct net_data *net_data = p;
+
+ res_ndestroy(net_data->res);
+ if (net_data->gr != NULL) {
+ (*net_data->gr->close)(net_data->gr);
+ net_data->gr = NULL;
+ }
+ if (net_data->pw != NULL) {
+ (*net_data->pw->close)(net_data->pw);
+ net_data->pw = NULL;
+ }
+ if (net_data->sv != NULL) {
+ (*net_data->sv->close)(net_data->sv);
+ net_data->sv = NULL;
+ }
+ if (net_data->pr != NULL) {
+ (*net_data->pr->close)(net_data->pr);
+ net_data->pr = NULL;
+ }
+ if (net_data->ho != NULL) {
+ (*net_data->ho->close)(net_data->ho);
+ net_data->ho = NULL;
+ }
+ if (net_data->nw != NULL) {
+ (*net_data->nw->close)(net_data->nw);
+ net_data->nw = NULL;
+ }
+ if (net_data->ng != NULL) {
+ (*net_data->ng->close)(net_data->ng);
+ net_data->ng = NULL;
+ }
+ if (net_data->ho_data != NULL) {
+ free(net_data->ho_data);
+ net_data->ho_data = NULL;
+ }
+ if (net_data->nw_data != NULL) {
+ free(net_data->nw_data);
+ net_data->nw_data = NULL;
+ }
+
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof *net_data);
+}
+
+/*%
+ * applications that need a specific config file other than
+ * _PATH_IRS_CONF should call net_data_init directly rather than letting
+ * the various wrapper functions make the first call. - brister
+ */
+
+struct net_data *
+net_data_init(const char *conf_file) {
+#ifdef DO_PTHREADS
+#ifndef LIBBIND_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+ static pthread_mutex_t keylock = LIBBIND_MUTEX_INITIALIZER;
+ struct net_data *net_data;
+
+ if (!once) {
+ if (pthread_mutex_lock(&keylock) != 0)
+ return (NULL);
+ if (!once) {
+ if (pthread_key_create(&key, net_data_destroy) != 0) {
+ (void)pthread_mutex_unlock(&keylock);
+ return (NULL);
+ }
+ once = 1;
+ }
+ if (pthread_mutex_unlock(&keylock) != 0)
+ return (NULL);
+ }
+ net_data = pthread_getspecific(key);
+#endif
+
+ if (net_data == NULL) {
+ net_data = net_data_create(conf_file);
+ if (net_data == NULL)
+ return (NULL);
+#ifdef DO_PTHREADS
+ if (pthread_setspecific(key, net_data) != 0) {
+ net_data_destroy(net_data);
+ return (NULL);
+ }
+#endif
+ }
+
+ return (net_data);
+}
+
+struct net_data *
+net_data_create(const char *conf_file) {
+ struct net_data *net_data;
+
+ net_data = memget(sizeof (struct net_data));
+ if (net_data == NULL)
+ return (NULL);
+ memset(net_data, 0, sizeof (struct net_data));
+
+ if ((net_data->irs = irs_gen_acc("", conf_file)) == NULL) {
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+#ifndef DO_PTHREADS
+ (*net_data->irs->res_set)(net_data->irs, &_res, NULL);
+#endif
+
+ net_data->res = (*net_data->irs->res_get)(net_data->irs);
+ if (net_data->res == NULL) {
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+
+ if ((net_data->res->options & RES_INIT) == 0U &&
+ res_ninit(net_data->res) == -1) {
+ (*net_data->irs->close)(net_data->irs);
+ memput(net_data, sizeof (struct net_data));
+ return (NULL);
+ }
+
+ return (net_data);
+}
+
+void
+net_data_minimize(struct net_data *net_data) {
+ res_nclose(net_data->res);
+}
+
+#ifdef _REENTRANT
+struct __res_state *
+__res_state(void) {
+ /* NULL param here means use the default config file. */
+ struct net_data *net_data = net_data_init(NULL);
+ if (net_data && net_data->res)
+ return (net_data->res);
+
+ return (&_res);
+}
+#else
+#ifdef __linux
+struct __res_state *
+__res_state(void) {
+ return (&_res);
+}
+#endif
+#endif
+
+int *
+__h_errno(void) {
+ /* NULL param here means use the default config file. */
+ struct net_data *net_data = net_data_init(NULL);
+ if (net_data && net_data->res)
+ return (&net_data->res->res_h_errno);
+#ifdef ORIGINAL_ISC_CODE
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+ return(&_res.res_h_errno);
+#else
+ return (&h_errno);
+#endif
+#else
+ return (&h_errno);
+#endif /* ORIGINAL_ISC_CODE */
+}
+
+void
+__h_errno_set(struct __res_state *res, int err) {
+
+
+#if (__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+ res->res_h_errno = err;
+#else
+ h_errno = res->res_h_errno = err;
+#endif
+}
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irs_data.h b/usr/src/lib/libresolv2_joy/common/irs/irs_data.h
new file mode 100644
index 0000000000..cb814fd8b1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irs_data.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs_data.h,v 1.3 2005/04/27 04:56:30 sra Exp $
+ */
+
+#ifndef __BIND_NOSTATIC
+
+#define net_data_init __net_data_init
+
+struct net_data {
+ struct irs_acc * irs;
+
+ struct irs_gr * gr;
+ struct irs_pw * pw;
+ struct irs_sv * sv;
+ struct irs_pr * pr;
+ struct irs_ho * ho;
+ struct irs_nw * nw;
+ struct irs_ng * ng;
+
+ struct group * gr_last;
+ struct passwd * pw_last;
+ struct servent * sv_last;
+ struct protoent * pr_last;
+ struct netent * nw_last; /*%< should have been ne_last */
+ struct nwent * nww_last;
+ struct hostent * ho_last;
+
+ unsigned int gr_stayopen :1;
+ unsigned int pw_stayopen :1;
+ unsigned int sv_stayopen :1;
+ unsigned int pr_stayopen :1;
+ unsigned int ho_stayopen :1;
+ unsigned int nw_stayopen :1;
+
+ void * nw_data;
+ void * ho_data;
+
+ struct __res_state * res; /*%< for gethostent.c */
+};
+
+extern struct net_data * net_data_init(const char *conf_file);
+extern void net_data_minimize(struct net_data *);
+
+#endif /*__BIND_NOSTATIC*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/irs_p.h b/usr/src/lib/libresolv2_joy/common/irs/irs_p.h
new file mode 100644
index 0000000000..2a0a933fce
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/irs_p.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs_p.h,v 1.3 2005/04/27 04:56:30 sra Exp $
+ */
+
+#ifndef _IRS_P_H_INCLUDED
+#define _IRS_P_H_INCLUDED
+
+#include <stdio.h>
+
+#include "pathnames.h"
+
+#define IRS_SV_MAXALIASES 35
+
+struct lcl_sv {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ struct servent serv;
+ char * serv_aliases[IRS_SV_MAXALIASES];
+};
+
+#define irs_nul_ng __irs_nul_ng
+#define map_v4v6_address __map_v4v6_address
+#define make_group_list __make_group_list
+#define irs_lclsv_fnxt __irs_lclsv_fnxt
+
+extern void map_v4v6_address(const char *src, char *dst);
+extern int make_group_list(struct irs_gr *, const char *,
+ gid_t, gid_t *, int *);
+extern struct irs_ng * irs_nul_ng(struct irs_acc *);
+extern struct servent * irs_lclsv_fnxt(struct lcl_sv *);
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl.c b/usr/src/lib/libresolv2_joy/common/irs/lcl.c
new file mode 100644
index 0000000000..9dd6967b87
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl.c,v 1.4 2005/04/27 04:56:30 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Forward. */
+
+static void lcl_close(struct irs_acc *);
+static struct __res_state * lcl_res_get(struct irs_acc *);
+static void lcl_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_lcl_acc(const char *options) {
+ struct irs_acc *acc;
+ struct lcl_p *lcl;
+
+ UNUSED(options);
+
+ if (!(acc = memget(sizeof *acc))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ if (!(lcl = memget(sizeof *lcl))) {
+ errno = ENOMEM;
+ free(acc);
+ return (NULL);
+ }
+ memset(lcl, 0x5e, sizeof *lcl);
+ lcl->res = NULL;
+ lcl->free_res = NULL;
+ acc->private = lcl;
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_lcl_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_lcl_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_lcl_sv;
+ acc->pr_map = irs_lcl_pr;
+ acc->ho_map = irs_lcl_ho;
+ acc->nw_map = irs_lcl_nw;
+ acc->ng_map = irs_lcl_ng;
+ acc->res_get = lcl_res_get;
+ acc->res_set = lcl_res_set;
+ acc->close = lcl_close;
+ return (acc);
+}
+
+/* Methods */
+static struct __res_state *
+lcl_res_get(struct irs_acc *this) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ lcl_res_set(this, res, free);
+ }
+
+ if ((lcl->res->options & RES_INIT) == 0U &&
+ res_ninit(lcl->res) < 0)
+ return (NULL);
+
+ return (lcl->res);
+}
+
+static void
+lcl_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl->res && lcl->free_res) {
+ res_nclose(lcl->res);
+ (*lcl->free_res)(lcl->res);
+ }
+
+ lcl->res = res;
+ lcl->free_res = free_res;
+}
+
+static void
+lcl_close(struct irs_acc *this) {
+ struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+ if (lcl) {
+ if (lcl->free_res)
+ (*lcl->free_res)(lcl->res);
+ memput(lcl, sizeof *lcl);
+ }
+ memput(this, sizeof *this);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_ho.c b/usr/src/lib/libresolv2_joy/common/irs/lcl_ho.c
new file mode 100644
index 0000000000..17c9a5e725
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_ho.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 1985, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
+/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define MAXALIASES 35
+#define MAXADDRS 35
+#define Max(a,b) ((a) > (b) ? (a) : (b))
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+struct pvt {
+ FILE * fp;
+ struct hostent host;
+ char * h_addr_ptrs[MAXADDRS + 1];
+ char * host_aliases[MAXALIASES];
+ char hostbuf[8*1024];
+ u_char host_addr[16]; /*%< IPv4 or IPv6 */
+ struct __res_state *res;
+ void (*free_res)(void *);
+};
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+
+/* Forward. */
+
+static void ho_close(struct irs_ho *this);
+static struct hostent * ho_byname(struct irs_ho *this, const char *name);
+static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
+ int af);
+static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ int len, int af);
+static struct hostent * ho_next(struct irs_ho *this);
+static void ho_rewind(struct irs_ho *this);
+static void ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void ho_res_set(struct irs_ho *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+ const struct addrinfo *pai);
+
+static size_t ns_namelen(const char *);
+static int init(struct irs_ho *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public. */
+
+struct irs_ho *
+irs_lcl_ho(struct irs_acc *this) {
+ struct irs_ho *ho;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(ho = memget(sizeof *ho))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ho, 0x5e, sizeof *ho);
+ ho->private = pvt;
+ ho->close = ho_close;
+ ho->byname = ho_byname;
+ ho->byname2 = ho_byname2;
+ ho->byaddr = ho_byaddr;
+ ho->next = ho_next;
+ ho->rewind = ho_rewind;
+ ho->minimize = ho_minimize;
+ ho->res_get = ho_res_get;
+ ho->res_set = ho_res_set;
+ ho->addrinfo = ho_addrinfo;
+ return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ ho_minimize(this);
+ if (pvt->fp)
+ (void) fclose(pvt->fp);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (pvt->res->options & RES_USE_INET6) {
+ hp = ho_byname2(this, name, AF_INET6);
+ if (hp)
+ return (hp);
+ }
+ return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+ char **hap;
+ size_t n;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ ho_rewind(this);
+ n = ns_namelen(name);
+ while ((hp = ho_next(this)) != NULL) {
+ size_t nn;
+
+ if (hp->h_addrtype != af)
+ continue;
+ nn = ns_namelen(hp->h_name);
+ if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0)
+ goto found;
+ for (hap = hp->h_aliases; *hap; hap++) {
+ nn = ns_namelen(*hap);
+ if (strncasecmp(*hap, name, Max(n, nn)) == 0)
+ goto found;
+ }
+ }
+ found:
+ if (!hp) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (hp);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ const u_char *uaddr = addr;
+ struct hostent *hp;
+ int size;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (af == AF_INET6 && len == IN6ADDRSZ &&
+ (!memcmp(uaddr, mapped, sizeof mapped) ||
+ !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
+ /* Unmap. */
+ addr = (const u_char *)addr + sizeof mapped;
+ uaddr += sizeof mapped;
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ switch (af) {
+ case AF_INET:
+ size = INADDRSZ;
+ break;
+ case AF_INET6:
+ size = IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ if (size > len) {
+ errno = EINVAL;
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+
+ /*
+ * Do the search.
+ */
+ ho_rewind(this);
+ while ((hp = ho_next(this)) != NULL) {
+ char **hap;
+
+ for (hap = hp->h_addr_list; *hap; hap++) {
+ const u_char *taddr = (const u_char *)*hap;
+ int taf = hp->h_addrtype;
+ int tlen = hp->h_length;
+
+ if (taf == AF_INET6 && tlen == IN6ADDRSZ &&
+ (!memcmp(taddr, mapped, sizeof mapped) ||
+ !memcmp(taddr, tunnelled, sizeof tunnelled))) {
+ /* Unmap. */
+ taddr += sizeof mapped;
+ taf = AF_INET;
+ tlen = INADDRSZ;
+ }
+ if (taf == af && tlen == len &&
+ !memcmp(taddr, uaddr, tlen))
+ goto found;
+ }
+ }
+ found:
+ if (!hp) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ return (NULL);
+ }
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (hp);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *cp, **q, *p;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, af, len, bufsiz, offset;
+
+ if (init(this) == -1)
+ return (NULL);
+
+ if (!pvt->fp)
+ ho_rewind(this);
+ if (!pvt->fp) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ bufp = pvt->hostbuf;
+ bufsiz = sizeof pvt->hostbuf;
+ offset = 0;
+ again:
+ if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) {
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+ if (dbuf)
+ free(dbuf);
+ return (NULL);
+ }
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+ if ((cp = strpbrk(p, "#\n")) != NULL)
+ *cp = '\0';
+ if (!(cp = strpbrk(p, " \t")))
+ goto again;
+ *cp++ = '\0';
+ if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) {
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) {
+ if (pvt->res->options & RES_USE_INET6) {
+ map_v4v6_address((char*)pvt->host_addr,
+ (char*)pvt->host_addr);
+ af = AF_INET6;
+ len = IN6ADDRSZ;
+ } else {
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+ } else {
+ goto again;
+ }
+ pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+ pvt->h_addr_ptrs[1] = NULL;
+ pvt->host.h_addr_list = pvt->h_addr_ptrs;
+ pvt->host.h_length = len;
+ pvt->host.h_addrtype = af;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ pvt->host.h_name = cp;
+ q = pvt->host.h_aliases = pvt->host_aliases;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->host_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+ if (dbuf)
+ free(dbuf);
+ RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+ return (&pvt->host);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_HOSTS, "r")))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+ if (pvt->res)
+ res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ ho_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+struct lcl_res_target {
+ struct lcl_res_target *next;
+ int family;
+};
+
+/* XXX */
+extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
+ const struct addrinfo *pai));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct hostent *hp;
+ struct lcl_res_target q, q2, *p;
+ struct addrinfo sentinel, *cur;
+
+ memset(&q, 0, sizeof(q2));
+ memset(&q2, 0, sizeof(q2));
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ switch(pai->ai_family) {
+ case AF_UNSPEC: /*%< INET6 then INET4 */
+ q.family = AF_INET6;
+ q.next = &q2;
+ q2.family = AF_INET;
+ break;
+ case AF_INET6:
+ q.family = AF_INET6;
+ break;
+ case AF_INET:
+ q.family = AF_INET;
+ break;
+ default:
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */
+ return(NULL);
+ }
+
+ for (p = &q; p; p = p->next) {
+ struct addrinfo *ai;
+
+ hp = (*this->byname2)(this, name, p->family);
+ if (hp == NULL) {
+ /* byname2 should've set an appropriate error */
+ continue;
+ }
+ if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+ (hp->h_addr_list[0] == NULL)) {
+ RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+ continue;
+ }
+
+ ai = hostent2addrinfo(hp, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL)
+ RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+
+ return(sentinel.ai_next);
+}
+
+/* Private. */
+
+static size_t
+ns_namelen(const char *s) {
+ int i;
+
+ for (i = strlen(s); i > 0 && s[i-1] == '.'; i--)
+ (void)NULL;
+ return ((size_t) i);
+}
+
+static int
+init(struct irs_ho *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !ho_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_ng.c b/usr/src/lib/libresolv2_joy/common/irs/lcl_ng.c
new file mode 100644
index 0000000000..319725ce70
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_ng.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl_ng.c,v 1.3 2005/04/27 04:56:31 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Definitions */
+
+#define NG_HOST 0 /*%< Host name */
+#define NG_USER 1 /*%< User name */
+#define NG_DOM 2 /*%< and Domain name */
+#define LINSIZ 1024 /*%< Length of netgroup file line */
+/*
+ * XXX Warning XXX
+ * This code is a hack-and-slash special. It realy needs to be
+ * rewritten with things like strdup, and realloc in mind.
+ * More reasonable data structures would not be a bad thing.
+ */
+
+/*%
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * endnetgrent().
+ *
+ * There are two linked lists:
+ * \li linelist is just used by setnetgrent() to parse the net group file via.
+ * parse_netgrp()
+ * \li netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+ struct linelist *l_next; /*%< Chain ptr. */
+ int l_parsed; /*%< Flag for cycles */
+ char * l_groupname; /*%< Name of netgroup */
+ char * l_line; /*%< Netgroup entrie(s) to be parsed */
+};
+
+struct ng_old_struct {
+ struct ng_old_struct *ng_next; /*%< Chain ptr */
+ char * ng_str[3]; /*%< Field pointers, see below */
+};
+
+struct pvt {
+ FILE *fp;
+ struct linelist *linehead;
+ struct ng_old_struct *nextgrp;
+ struct {
+ struct ng_old_struct *gr;
+ char *grname;
+ } grouphead;
+};
+
+/* Forward */
+
+static void ng_rewind(struct irs_ng *, const char*);
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *);
+static void ng_minimize(struct irs_ng *);
+
+static int parse_netgrp(struct irs_ng *, const char*);
+static struct linelist *read_for_group(struct irs_ng *, const char *);
+static void freelists(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_lcl_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(ng, sizeof *ng);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ ng->private = pvt;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL)
+ fclose(pvt->fp);
+ freelists(this);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+/*%
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
+ fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+
+ if (pvt->fp == NULL || pvt->grouphead.gr == NULL ||
+ strcmp(group, pvt->grouphead.grname)) {
+ freelists(this);
+ if (pvt->fp != NULL)
+ fclose(pvt->fp);
+ pvt->fp = fopen(_PATH_NETGROUP, "r");
+ if (pvt->fp != NULL) {
+ if (parse_netgrp(this, group))
+ freelists(this);
+ if (!(pvt->grouphead.grname = strdup(group)))
+ freelists(this);
+ fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+ }
+ pvt->nextgrp = pvt->grouphead.gr;
+}
+
+/*%
+ * Get the next netgroup off the list.
+ */
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->nextgrp) {
+ *host = pvt->nextgrp->ng_str[NG_HOST];
+ *user = pvt->nextgrp->ng_str[NG_USER];
+ *domain = pvt->nextgrp->ng_str[NG_DOM];
+ pvt->nextgrp = pvt->nextgrp->ng_next;
+ return (1);
+ }
+ return (0);
+}
+
+/*%
+ * Search for a match in a netgroup.
+ */
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *host, const char *user, const char *domain)
+{
+ const char *ng_host, *ng_user, *ng_domain;
+
+ ng_rewind(this, name);
+ while (ng_next(this, &ng_host, &ng_user, &ng_domain))
+ if ((host == NULL || ng_host == NULL ||
+ !strcmp(host, ng_host)) &&
+ (user == NULL || ng_user == NULL ||
+ !strcmp(user, ng_user)) &&
+ (domain == NULL || ng_domain == NULL ||
+ !strcmp(domain, ng_domain))) {
+ freelists(this);
+ return (1);
+ }
+ freelists(this);
+ return (0);
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+/* Private */
+
+/*%
+ * endnetgrent() - cleanup
+ */
+static void
+freelists(struct irs_ng *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct linelist *lp, *olp;
+ struct ng_old_struct *gp, *ogp;
+
+ lp = pvt->linehead;
+ while (lp) {
+ olp = lp;
+ lp = lp->l_next;
+ free(olp->l_groupname);
+ free(olp->l_line);
+ free((char *)olp);
+ }
+ pvt->linehead = NULL;
+ if (pvt->grouphead.grname) {
+ free(pvt->grouphead.grname);
+ pvt->grouphead.grname = NULL;
+ }
+ gp = pvt->grouphead.gr;
+ while (gp) {
+ ogp = gp;
+ gp = gp->ng_next;
+ if (ogp->ng_str[NG_HOST])
+ free(ogp->ng_str[NG_HOST]);
+ if (ogp->ng_str[NG_USER])
+ free(ogp->ng_str[NG_USER]);
+ if (ogp->ng_str[NG_DOM])
+ free(ogp->ng_str[NG_DOM]);
+ free((char *)ogp);
+ }
+ pvt->grouphead.gr = NULL;
+}
+
+/*%
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *spos, *epos;
+ int len, strpos;
+ char *pos, *gpos;
+ struct ng_old_struct *grp;
+ struct linelist *lp = pvt->linehead;
+
+ /*
+ * First, see if the line has already been read in.
+ */
+ while (lp) {
+ if (!strcmp(group, lp->l_groupname))
+ break;
+ lp = lp->l_next;
+ }
+ if (lp == NULL &&
+ (lp = read_for_group(this, group)) == NULL)
+ return (1);
+ if (lp->l_parsed) {
+ /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
+ return (1);
+ } else
+ lp->l_parsed = 1;
+ pos = lp->l_line;
+ while (*pos != '\0') {
+ if (*pos == '(') {
+ if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
+ freelists(this);
+ errno = ENOMEM;
+ return (1);
+ }
+ memset(grp, 0, sizeof (struct ng_old_struct));
+ grp->ng_next = pvt->grouphead.gr;
+ pvt->grouphead.gr = grp;
+ pos++;
+ gpos = strsep(&pos, ")");
+ for (strpos = 0; strpos < 3; strpos++) {
+ if ((spos = strsep(&gpos, ","))) {
+ while (*spos == ' ' || *spos == '\t')
+ spos++;
+ if ((epos = strpbrk(spos, " \t"))) {
+ *epos = '\0';
+ len = epos - spos;
+ } else
+ len = strlen(spos);
+ if (len > 0) {
+ if(!(grp->ng_str[strpos]
+ = (char *)
+ malloc(len + 1))) {
+ freelists(this);
+ return (1);
+ }
+ memcpy(grp->ng_str[strpos],
+ spos,
+ len + 1);
+ }
+ } else
+ goto errout;
+ }
+ } else {
+ spos = strsep(&pos, ", \t");
+ if (spos != NULL && parse_netgrp(this, spos)) {
+ freelists(this);
+ return (1);
+ }
+ }
+ if (pos == NULL)
+ break;
+ while (*pos == ' ' || *pos == ',' || *pos == '\t')
+ pos++;
+ }
+ return (0);
+ errout:
+ /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
+ spos);*/
+ return (1);
+}
+
+/*%
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(struct irs_ng *this, const char *group) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *pos, *spos, *linep = NULL, *olinep;
+ int len, olen, cont;
+ struct linelist *lp;
+ char line[LINSIZ + 1];
+
+ while (fgets(line, LINSIZ, pvt->fp) != NULL) {
+ pos = line;
+ if (*pos == '#')
+ continue;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ spos = pos;
+ while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+ *pos != '\0')
+ pos++;
+ len = pos - spos;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\n' && *pos != '\0') {
+ if (!(lp = malloc(sizeof (*lp)))) {
+ freelists(this);
+ return (NULL);
+ }
+ lp->l_parsed = 0;
+ if (!(lp->l_groupname = malloc(len + 1))) {
+ free(lp);
+ freelists(this);
+ return (NULL);
+ }
+ memcpy(lp->l_groupname, spos, len);
+ *(lp->l_groupname + len) = '\0';
+ len = strlen(pos);
+ olen = 0;
+ olinep = NULL;
+
+ /*
+ * Loop around handling line continuations.
+ */
+ do {
+ if (*(pos + len - 1) == '\n')
+ len--;
+ if (*(pos + len - 1) == '\\') {
+ len--;
+ cont = 1;
+ } else
+ cont = 0;
+ if (len > 0) {
+ if (!(linep = malloc(olen + len + 1))){
+ if (olen > 0)
+ free(olinep);
+ free(lp->l_groupname);
+ free(lp);
+ freelists(this);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (olen > 0) {
+ memcpy(linep, olinep, olen);
+ free(olinep);
+ }
+ memcpy(linep + olen, pos, len);
+ olen += len;
+ *(linep + olen) = '\0';
+ olinep = linep;
+ }
+ if (cont) {
+ if (fgets(line, LINSIZ, pvt->fp)) {
+ pos = line;
+ len = strlen(pos);
+ } else
+ cont = 0;
+ }
+ } while (cont);
+ lp->l_line = linep;
+ lp->l_next = pvt->linehead;
+ pvt->linehead = lp;
+
+ /*
+ * If this is the one we wanted, we are done.
+ */
+ if (!strcmp(lp->l_groupname, group))
+ return (lp);
+ }
+ }
+ return (NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_nw.c b/usr/src/lib/libresolv2_joy/common/irs/lcl_nw.c
new file mode 100644
index 0000000000..2e5cd55a6c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_nw.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_nw.c,v 1.4 2005/04/27 04:56:31 sra Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $ */
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ struct nwent net;
+ char * aliases[MAXALIASES];
+ char addr[MAXADDRSIZE];
+ struct __res_state * res;
+ void (*free_res)(void *);
+};
+
+/* Forward */
+
+static void nw_close(struct irs_nw *);
+static struct nwent * nw_byname(struct irs_nw *, const char *, int);
+static struct nwent * nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent * nw_next(struct irs_nw *);
+static void nw_rewind(struct irs_nw *);
+static void nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void nw_res_set(struct irs_nw *this,
+ struct __res_state *res,
+ void (*free_res)(void *));
+
+static int init(struct irs_nw *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_nw *
+irs_lcl_nw(struct irs_acc *this) {
+ struct irs_nw *nw;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if (!(pvt = memget(sizeof *pvt))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ if (!(nw = memget(sizeof *nw))) {
+ memput(pvt, sizeof *pvt);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nw, 0x5e, sizeof *nw);
+ nw->private = pvt;
+ nw->close = nw_close;
+ nw->byname = nw_byname;
+ nw->byaddr = nw_byaddr;
+ nw->next = nw_next;
+ nw->rewind = nw_rewind;
+ nw->minimize = nw_minimize;
+ nw->res_get = nw_res_get;
+ nw->res_set = nw_res_set;
+ return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ nw_minimize(this);
+ if (pvt->res && pvt->free_res)
+ (*pvt->free_res)(pvt->res);
+ if (pvt->fp)
+ (void)fclose(pvt->fp);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+ struct nwent *p;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ nw_rewind(this);
+ while ((p = nw_next(this)) != NULL)
+ if (p->n_addrtype == type && p->n_length == length)
+ if (bitncmp(p->n_addr, net, length) == 0)
+ break;
+ return (p);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+ struct nwent *p;
+ char **ap;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ nw_rewind(this);
+ while ((p = nw_next(this)) != NULL) {
+ if (ns_samename(p->n_name, name) == 1 &&
+ p->n_addrtype == type)
+ break;
+ for (ap = p->n_aliases; *ap; ap++)
+ if ((ns_samename(*ap, name) == 1) &&
+ (p->n_addrtype == type))
+ goto found;
+ }
+ found:
+ return (p);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_NETWORKS, "r")))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ struct nwent *ret = NULL;
+ char *p, *cp, **q;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, bufsiz, offset = 0;
+
+ if (init(this) == -1)
+ return(NULL);
+
+ if (pvt->fp == NULL)
+ nw_rewind(this);
+ if (pvt->fp == NULL) {
+ RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+ return (NULL);
+ }
+ bufp = pvt->line;
+ bufsiz = sizeof(pvt->line);
+
+ again:
+ p = fgets(bufp + offset, bufsiz - offset, pvt->fp);
+ if (p == NULL)
+ goto cleanup;
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ pvt->net.n_name = p;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ pvt->net.n_length = inet_net_pton(AF_INET, cp, pvt->addr,
+ sizeof pvt->addr);
+ if (pvt->net.n_length < 0)
+ goto again;
+ pvt->net.n_addrtype = AF_INET;
+ pvt->net.n_addr = pvt->addr;
+ q = pvt->net.n_aliases = pvt->aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->aliases[MAXALIASES - 1])
+ *q++ = cp;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+ ret = &pvt->net;
+
+ cleanup:
+ if (dbuf)
+ free(dbuf);
+
+ return (ret);
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res)
+ res_nclose(pvt->res);
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (!res) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(res, 0, sizeof *res);
+ nw_res_set(this, res, free);
+ }
+
+ return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->res && pvt->free_res) {
+ res_nclose(pvt->res);
+ (*pvt->free_res)(pvt->res);
+ }
+
+ pvt->res = res;
+ pvt->free_res = free_res;
+}
+
+static int
+init(struct irs_nw *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (!pvt->res && !nw_res_get(this))
+ return (-1);
+ if (((pvt->res->options & RES_INIT) == 0U) &&
+ res_ninit(pvt->res) == -1)
+ return (-1);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_p.h b/usr/src/lib/libresolv2_joy/common/irs/lcl_p.h
new file mode 100644
index 0000000000..e3f4f009cb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_p.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: lcl_p.h,v 1.3 2005/04/27 04:56:31 sra Exp $
+ */
+
+/*! \file
+ * \brief
+ * lcl_p.h - private include file for the local accessor functions.
+ */
+
+#ifndef _LCL_P_H_INCLUDED
+#define _LCL_P_H_INCLUDED
+
+/*%
+ * Object state.
+ */
+struct lcl_p {
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc * irs_lcl_acc __P((const char *));
+extern struct irs_gr * irs_lcl_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_lcl_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_lcl_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_lcl_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_lcl_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_lcl_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_lcl_ng __P((struct irs_acc *));
+
+#endif /*_LCL_P_H_INCLUDED*/
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_pr.c b/usr/src/lib/libresolv2_joy/common/irs/lcl_pr.c
new file mode 100644
index 0000000000..e1538530eb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_pr.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_pr.c,v 1.4 2006/03/09 23:57:56 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifndef _PATH_PROTOCOLS
+#define _PATH_PROTOCOLS "/etc/protocols"
+#endif
+#define MAXALIASES 35
+
+/* Types */
+
+struct pvt {
+ FILE * fp;
+ char line[BUFSIZ+1];
+ char * dbuf;
+ struct protoent proto;
+ char * proto_aliases[MAXALIASES];
+};
+
+/* Forward */
+
+static void pr_close(struct irs_pr *);
+static struct protoent * pr_next(struct irs_pr *);
+static struct protoent * pr_byname(struct irs_pr *, const char *);
+static struct protoent * pr_bynumber(struct irs_pr *, int);
+static void pr_rewind(struct irs_pr *);
+static void pr_minimize(struct irs_pr *);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_pr *
+irs_lcl_pr(struct irs_acc *this) {
+ struct irs_pr *pr;
+ struct pvt *pvt;
+
+ if (!(pr = memget(sizeof *pr))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ if (!(pvt = memget(sizeof *pvt))) {
+ memput(pr, sizeof *this);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ pr->private = pvt;
+ pr->close = pr_close;
+ pr->byname = pr_byname;
+ pr->bynumber = pr_bynumber;
+ pr->next = pr_next;
+ pr->rewind = pr_rewind;
+ pr->minimize = pr_minimize;
+ pr->res_get = NULL;
+ pr->res_set = NULL;
+ return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp)
+ (void) fclose(pvt->fp);
+ if (pvt->dbuf)
+ free(pvt->dbuf);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+
+ struct protoent *p;
+ char **cp;
+
+ pr_rewind(this);
+ while ((p = pr_next(this))) {
+ if (!strcmp(p->p_name, name))
+ goto found;
+ for (cp = p->p_aliases; *cp; cp++)
+ if (!strcmp(*cp, name))
+ goto found;
+ }
+ found:
+ return (p);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+ struct protoent *p;
+
+ pr_rewind(this);
+ while ((p = pr_next(this)))
+ if (p->p_proto == proto)
+ break;
+ return (p);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp) {
+ if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->fp);
+ }
+ if (!(pvt->fp = fopen(_PATH_PROTOCOLS, "r" )))
+ return;
+ if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+ char *p, *cp, **q;
+ char *bufp, *ndbuf, *dbuf = NULL;
+ int c, bufsiz, offset;
+
+ if (!pvt->fp)
+ pr_rewind(this);
+ if (!pvt->fp)
+ return (NULL);
+ if (pvt->dbuf) {
+ free(pvt->dbuf);
+ pvt->dbuf = NULL;
+ }
+ bufp = pvt->line;
+ bufsiz = BUFSIZ;
+ offset = 0;
+ again:
+ if ((p = fgets(bufp + offset, bufsiz - offset, pvt->fp)) == NULL) {
+ if (dbuf)
+ free(dbuf);
+ return (NULL);
+ }
+ if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+ /* allocate space for longer line */
+ if (dbuf == NULL) {
+ if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+ strcpy(ndbuf, bufp);
+ } else
+ ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+ if (ndbuf) {
+ dbuf = ndbuf;
+ bufp = dbuf;
+ bufsiz += GROWBUF;
+ offset = strlen(dbuf);
+ } else {
+ /* allocation failed; skip this long line */
+ while ((c = getc(pvt->fp)) != EOF)
+ if (c == '\n')
+ break;
+ if (c != EOF)
+ ungetc(c, pvt->fp);
+ }
+ goto again;
+ }
+
+ p -= offset;
+ offset = 0;
+
+ if (*p == '#')
+ goto again;
+ cp = strpbrk(p, "#\n");
+ if (cp != NULL)
+ *cp = '\0';
+ pvt->proto.p_name = p;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = strpbrk(cp, " \t");
+ if (p != NULL)
+ *p++ = '\0';
+ pvt->proto.p_proto = atoi(cp);
+ q = pvt->proto.p_aliases = pvt->proto_aliases;
+ if (p != NULL) {
+ cp = p;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &pvt->proto_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ }
+ *q = NULL;
+ pvt->dbuf = dbuf;
+ return (&pvt->proto);
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->fp != NULL) {
+ (void)fclose(pvt->fp);
+ pvt->fp = NULL;
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/lcl_sv.c b/usr/src/lib/libresolv2_joy/common/irs/lcl_sv.c
new file mode 100644
index 0000000000..ad6526430c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/lcl_sv.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_sv.c,v 1.4 2005/04/27 04:56:31 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Types */
+
+struct pvt {
+#ifdef IRS_LCL_SV_DB
+ DB * dbh;
+ int dbf;
+#endif
+ struct lcl_sv sv;
+};
+
+/* Forward */
+
+static void sv_close(struct irs_sv*);
+static struct servent * sv_next(struct irs_sv *);
+static struct servent * sv_byname(struct irs_sv *, const char *,
+ const char *);
+static struct servent * sv_byport(struct irs_sv *, int, const char *);
+static void sv_rewind(struct irs_sv *);
+static void sv_minimize(struct irs_sv *);
+/*global*/ struct servent * irs_lclsv_fnxt(struct lcl_sv *);
+#ifdef IRS_LCL_SV_DB
+static struct servent * sv_db_rec(struct lcl_sv *, DBT *, DBT *);
+#endif
+
+/* Portability */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_sv *
+irs_lcl_sv(struct irs_acc *this) {
+ struct irs_sv *sv;
+ struct pvt *pvt;
+
+ UNUSED(this);
+
+ if ((sv = memget(sizeof *sv)) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(sv, 0x5e, sizeof *sv);
+ if ((pvt = memget(sizeof *pvt)) == NULL) {
+ memput(sv, sizeof *sv);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(pvt, 0, sizeof *pvt);
+ sv->private = pvt;
+ sv->close = sv_close;
+ sv->next = sv_next;
+ sv->byname = sv_byname;
+ sv->byport = sv_byport;
+ sv->rewind = sv_rewind;
+ sv->minimize = sv_minimize;
+ sv->res_get = NULL;
+ sv->res_set = NULL;
+#ifdef IRS_LCL_SV_DB
+ pvt->dbf = R_FIRST;
+#endif
+ return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL)
+ (*pvt->dbh->close)(pvt->dbh);
+#endif
+ if (pvt->sv.fp)
+ fclose(pvt->sv.fp);
+ memput(pvt, sizeof *pvt);
+ memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+ struct pvt *pvt = (struct pvt *)this->private;
+#endif
+ struct servent *p;
+ char **cp;
+
+ sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+
+ /* Note that (sizeof "/") == 2. */
+ if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0)
+ > sizeof pvt->sv.line)
+ goto try_local;
+ key.data = pvt->sv.line;
+ key.size = SPRINTF((pvt->sv.line, "%s/%s", name,
+ proto ? proto : "")) + 1;
+ if (proto != NULL) {
+ if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+ return (NULL);
+ } else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+ != 0)
+ return (NULL);
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+ try_local:
+#endif
+
+ while ((p = sv_next(this))) {
+ if (strcmp(name, p->s_name) == 0)
+ goto gotname;
+ for (cp = p->s_aliases; *cp; cp++)
+ if (strcmp(name, *cp) == 0)
+ goto gotname;
+ continue;
+ gotname:
+ if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+ break;
+ }
+ return (p);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+ struct pvt *pvt = (struct pvt *)this->private;
+#endif
+ struct servent *p;
+
+ sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+ u_short *ports;
+
+ ports = (u_short *)pvt->sv.line;
+ ports[0] = 0;
+ ports[1] = port;
+ key.data = ports;
+ key.size = sizeof(u_short) * 2;
+ if (proto && *proto) {
+ strncpy((char *)ports + key.size, proto,
+ BUFSIZ - key.size);
+ key.size += strlen((char *)ports + key.size) + 1;
+ if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+ return (NULL);
+ } else {
+ if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+ != 0)
+ return (NULL);
+ }
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+#endif
+ while ((p = sv_next(this))) {
+ if (p->s_port != port)
+ continue;
+ if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+ break;
+ }
+ return (p);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+ if (pvt->sv.fp) {
+ if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0)
+ return;
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+#ifdef IRS_LCL_SV_DB
+ pvt->dbf = R_FIRST;
+ if (pvt->dbh != NULL)
+ return;
+ pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL);
+ if (pvt->dbh != NULL) {
+ if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) {
+ (*pvt->dbh->close)(pvt->dbh);
+ pvt->dbh = NULL;
+ }
+ return;
+ }
+#endif
+ if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL)
+ return;
+ if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) {
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh == NULL && pvt->sv.fp == NULL)
+#else
+ if (pvt->sv.fp == NULL)
+#endif
+ sv_rewind(this);
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ DBT key, data;
+
+ while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){
+ pvt->dbf = R_NEXT;
+ if (((char *)key.data)[0])
+ continue;
+ return (sv_db_rec(&pvt->sv, &key, &data));
+ }
+ }
+#endif
+
+ if (pvt->sv.fp == NULL)
+ return (NULL);
+ return (irs_lclsv_fnxt(&pvt->sv));
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+ struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+ if (pvt->dbh != NULL) {
+ (*pvt->dbh->close)(pvt->dbh);
+ pvt->dbh = NULL;
+ }
+#endif
+ if (pvt->sv.fp != NULL) {
+ (void)fclose(pvt->sv.fp);
+ pvt->sv.fp = NULL;
+ }
+}
+
+/* Quasipublic. */
+
+struct servent *
+irs_lclsv_fnxt(struct lcl_sv *sv) {
+ char *p, *cp, **q;
+
+ again:
+ if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL)
+ return (NULL);
+ if (*p == '#')
+ goto again;
+ sv->serv.s_name = p;
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ goto again;
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ goto again;
+ sv->serv.s_port = htons((u_short)strtol(p, &cp, 10));
+ if (cp == p || (*cp != '/' && *cp != ','))
+ goto again;
+ p = cp + 1;
+ sv->serv.s_proto = p;
+
+ q = sv->serv.s_aliases = sv->serv_aliases;
+
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+
+ while (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ if (*p == '\0' || *p == '#' || *p == '\n')
+ break;
+ if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1])
+ *q++ = p;
+ while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+ ++p;
+ }
+
+ *p = '\0';
+ *q = NULL;
+ return (&sv->serv);
+}
+
+/* Private. */
+
+#ifdef IRS_LCL_SV_DB
+static struct servent *
+sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) {
+ char *p, **q;
+ int n;
+
+ p = data->data;
+ p[data->size - 1] = '\0'; /*%< should be, but we depend on it */
+ if (((char *)key->data)[0] == '\0') {
+ if (key->size < sizeof(u_short)*2 || data->size < 2)
+ return (NULL);
+ sv->serv.s_port = ((u_short *)key->data)[1];
+ n = strlen(p) + 1;
+ if ((size_t)n > sizeof(sv->line)) {
+ n = sizeof(sv->line);
+ }
+ memcpy(sv->line, p, n);
+ sv->serv.s_name = sv->line;
+ if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+ *(sv->serv.s_proto)++ = '\0';
+ p += n;
+ data->size -= n;
+ } else {
+ if (data->size < sizeof(u_short) + 1)
+ return (NULL);
+ if (key->size > sizeof(sv->line))
+ key->size = sizeof(sv->line);
+ ((char *)key->data)[key->size - 1] = '\0';
+ memcpy(sv->line, key->data, key->size);
+ sv->serv.s_name = sv->line;
+ if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+ *(sv->serv.s_proto)++ = '\0';
+ sv->serv.s_port = *(u_short *)data->data;
+ p += sizeof(u_short);
+ data->size -= sizeof(u_short);
+ }
+ q = sv->serv.s_aliases = sv->serv_aliases;
+ while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) {
+
+ *q++ = p;
+ n = strlen(p) + 1;
+ data->size -= n;
+ p += n;
+ }
+ *q = NULL;
+ return (&sv->serv);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/nis.c b/usr/src/lib/libresolv2_joy/common/irs/nis.c
new file mode 100644
index 0000000000..ac1796543c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/nis.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis.c,v 1.3 2005/04/27 04:56:32 sra Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifdef WANT_IRS_NIS
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifdef T_NULL
+#undef T_NULL /* Silence re-definition warning of T_NULL. */
+#endif
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "nis_p.h"
+
+/* Forward */
+
+static void nis_close(struct irs_acc *);
+static struct __res_state * nis_res_get(struct irs_acc *);
+static void nis_res_set(struct irs_acc *, struct __res_state *,
+ void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_nis_acc(const char *options) {
+ struct nis_p *nis;
+ struct irs_acc *acc;
+ char *domain;
+
+ UNUSED(options);
+
+ if (yp_get_default_domain(&domain) != 0)
+ return (NULL);
+ if (!(nis = memget(sizeof *nis))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(nis, 0, sizeof *nis);
+ if (!(acc = memget(sizeof *acc))) {
+ memput(nis, sizeof *nis);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(acc, 0x5e, sizeof *acc);
+ acc->private = nis;
+ nis->domain = strdup(domain);
+#ifdef WANT_IRS_GR
+ acc->gr_map = irs_nis_gr;
+#else
+ acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+ acc->pw_map = irs_nis_pw;
+#else
+ acc->pw_map = NULL;
+#endif
+ acc->sv_map = irs_nis_sv;
+ acc->pr_map = irs_nis_pr;
+ acc->ho_map = irs_nis_ho;
+ acc->nw_map = irs_nis_nw;
+ acc->ng_map = irs_nis_ng;
+ acc->res_get = nis_res_get;
+ acc->res_set = nis_res_set;
+ acc->close = nis_close;
+ return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+nis_res_get(struct irs_acc *this) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res == NULL) {
+ struct __res_state *res;
+ res = (struct __res_state *)malloc(sizeof *res);
+ if (res == NULL)
+ return (NULL);
+ memset(res, 0, sizeof *res);
+ nis_res_set(this, res, free);
+ }
+
+ if ((nis->res->options & RES_INIT) == 0 &&
+ res_ninit(nis->res) < 0)
+ return (NULL);
+
+ return (nis->res);
+}
+
+static void
+nis_res_set(struct irs_acc *this, struct __res_state *res,
+ void (*free_res)(void *)) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res && nis->free_res) {
+ res_nclose(nis->res);
+ (*nis->free_res)(nis->res);
+ }
+
+ nis->res = res;
+ nis->free_res = free_res;
+}
+
+static void
+nis_close(struct irs_acc *this) {
+ struct nis_p *nis = (struct nis_p *)this->private;
+
+ if (nis->res && nis->free_res)
+ (*nis->free_res)(nis->res);
+ free(nis->domain);
+ memput(nis, sizeof *nis);
+ memput(this, sizeof *this);
+}
+
+#endif /*WANT_IRS_NIS*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/nis_p.h b/usr/src/lib/libresolv2_joy/common/irs/nis_p.h
new file mode 100644
index 0000000000..70e2948d67
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/nis_p.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: nis_p.h,v 1.3 2005/04/27 04:56:33 sra Exp $
+ */
+
+/*! \file
+ * \brief
+ * nis_p.h - private include file for the NIS functions.
+ */
+
+/*%
+ * Object state.
+ */
+struct nis_p {
+ char * domain;
+ struct __res_state * res;
+ void (*free_res) __P((void *));
+};
+
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_nis_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_nis_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_nis_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_nis_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_nis_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_nis_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_nis_ng __P((struct irs_acc *));
diff --git a/usr/src/lib/libresolv2_joy/common/irs/nul_ng.c b/usr/src/lib/libresolv2_joy/common/irs/nul_ng.c
new file mode 100644
index 0000000000..504813bde1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/nul_ng.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nul_ng.c,v 1.3 2005/04/27 04:56:34 sra Exp $";
+#endif
+
+/*! \file
+ * \brief
+ * nul_ng.c - the netgroup accessor null map
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Forward. */
+
+static void ng_close(struct irs_ng *);
+static int ng_next(struct irs_ng *, const char **,
+ const char **, const char **);
+static int ng_test(struct irs_ng *,
+ const char *, const char *,
+ const char *, const char *);
+static void ng_rewind(struct irs_ng *, const char *);
+static void ng_minimize(struct irs_ng *);
+
+/* Public. */
+
+struct irs_ng *
+irs_nul_ng(struct irs_acc *this) {
+ struct irs_ng *ng;
+
+ UNUSED(this);
+
+ if (!(ng = memget(sizeof *ng))) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(ng, 0x5e, sizeof *ng);
+ ng->private = NULL;
+ ng->close = ng_close;
+ ng->next = ng_next;
+ ng->test = ng_test;
+ ng->rewind = ng_rewind;
+ ng->minimize = ng_minimize;
+ return (ng);
+}
+
+/* Methods. */
+
+static void
+ng_close(struct irs_ng *this) {
+ memput(this, sizeof *this);
+}
+
+/* ARGSUSED */
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+ const char **domain)
+{
+ UNUSED(this);
+ UNUSED(host);
+ UNUSED(user);
+ UNUSED(domain);
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+ const char *user, const char *host, const char *domain)
+{
+ UNUSED(this);
+ UNUSED(name);
+ UNUSED(user);
+ UNUSED(host);
+ UNUSED(domain);
+ errno = ENODEV;
+ return (-1);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *netgroup) {
+ UNUSED(this);
+ UNUSED(netgroup);
+ /* NOOP */
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+ UNUSED(this);
+ /* NOOP */
+}
diff --git a/usr/src/lib/libresolv2_joy/common/irs/pathnames.h b/usr/src/lib/libresolv2_joy/common/irs/pathnames.h
new file mode 100644
index 0000000000..1646842155
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/pathnames.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: pathnames.h,v 1.3 2005/04/27 04:56:34 sra Exp $
+ */
+
+#ifndef _PATH_IRS_CONF
+#define _PATH_IRS_CONF "/etc/irs.conf"
+#endif
+
+#ifndef _PATH_NETWORKS
+#define _PATH_NETWORKS "/etc/networks"
+#endif
+
+#ifndef _PATH_GROUP
+#define _PATH_GROUP "/etc/group"
+#endif
+
+#ifndef _PATH_NETGROUP
+#define _PATH_NETGROUP "/etc/netgroup"
+#endif
+
+#ifndef _PATH_SERVICES
+#define _PATH_SERVICES "/etc/services"
+#endif
+
+#ifdef IRS_LCL_SV_DB
+#ifndef _PATH_SERVICES_DB
+#define _PATH_SERVICES_DB _PATH_SERVICES ".db"
+#endif
+#endif
+
+#ifndef _PATH_HESIOD_CONF
+#define _PATH_HESIOD_CONF "/etc/hesiod.conf"
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/irs/util.c b/usr/src/lib/libresolv2_joy/common/irs/util.c
new file mode 100644
index 0000000000..9c70eabddc
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/irs/util.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: util.c,v 1.3 2005/04/27 04:56:34 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+void
+map_v4v6_address(const char *src, char *dst) {
+ u_char *p = (u_char *)dst;
+ char tmp[NS_INADDRSZ];
+ int i;
+
+ /* Stash a temporary copy so our caller can update in place. */
+ memcpy(tmp, src, NS_INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ for (i = 0; i < 10; i++)
+ *p++ = 0x00;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ /* Retrieve the saved copy and we're done. */
+ memcpy((void*)p, tmp, NS_INADDRSZ);
+}
+
+int
+make_group_list(struct irs_gr *this, const char *name,
+ gid_t basegid, gid_t *groups, int *ngroups)
+{
+ struct group *grp;
+ int i, ng;
+ int ret, maxgroups;
+
+ ret = -1;
+ ng = 0;
+ maxgroups = *ngroups;
+ /*
+ * When installing primary group, duplicate it;
+ * the first element of groups is the effective gid
+ * and will be overwritten when a setgid file is executed.
+ */
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = basegid;
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = basegid;
+ /*
+ * Scan the group file to find additional groups.
+ */
+ (*this->rewind)(this);
+ while ((grp = (*this->next)(this)) != NULL) {
+ if ((gid_t)grp->gr_gid == basegid)
+ continue;
+ for (i = 0; grp->gr_mem[i]; i++) {
+ if (!strcmp(grp->gr_mem[i], name)) {
+ if (ng >= maxgroups)
+ goto done;
+ groups[ng++] = grp->gr_gid;
+ break;
+ }
+ }
+ }
+ ret = 0;
+ done:
+ *ngroups = ng;
+ return (ret);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/assertions.c b/usr/src/lib/libresolv2_joy/common/isc/assertions.c
new file mode 100644
index 0000000000..b71e5a32d3
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/assertions.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997, 1999, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: assertions.c,v 1.5 2008/11/14 02:36:51 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+/*
+ * Forward.
+ */
+
+static void default_assertion_failed(const char *, int, assertion_type,
+ const char *, int);
+
+/*
+ * Public.
+ */
+
+assertion_failure_callback __assertion_failed = default_assertion_failed;
+
+void
+set_assertion_failure_callback(assertion_failure_callback f) {
+ if (f == NULL)
+ __assertion_failed = default_assertion_failed;
+ else
+ __assertion_failed = f;
+}
+
+const char *
+assertion_type_to_text(assertion_type type) {
+ const char *result;
+
+ switch (type) {
+ case assert_require:
+ result = "REQUIRE";
+ break;
+ case assert_ensure:
+ result = "ENSURE";
+ break;
+ case assert_insist:
+ result = "INSIST";
+ break;
+ case assert_invariant:
+ result = "INVARIANT";
+ break;
+ default:
+ result = NULL;
+ }
+ return (result);
+}
+
+/*
+ * Private.
+ */
+
+/* coverity[+kill] */
+static void
+default_assertion_failed(const char *file, int line, assertion_type type,
+ const char *cond, int print_errno)
+{
+ fprintf(stderr, "%s:%d: %s(%s)%s%s failed.\n",
+ file, line, assertion_type_to_text(type), cond,
+ (print_errno) ? ": " : "",
+ (print_errno) ? strerror(errno) : "");
+ abort();
+ /* NOTREACHED */
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/base64.c b/usr/src/lib/libresolv2_joy/common/isc/base64.c
new file mode 100644
index 0000000000..79c35722b1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/base64.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: base64.c,v 1.4 2005/04/27 04:56:34 sra Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef ORIGINAL_ISC_CODE
+#pragma weak __b64_ntop = b64_ntop
+#pragma weak __b64_pton = b64_pton
+#endif /* ORIGINAL_ISC_CODE */
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2U < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0U != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1U)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /*%< Returned value doesn't count \\0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /*%< Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /*%< A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /*%< We got a pad char. */
+ ch = *src++; /*%< Skip it, get next. */
+ switch (state) {
+ case 0: /*%< Invalid = in first position */
+ case 1: /*%< Invalid = in second position */
+ return (-1);
+
+ case 2: /*%< Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /*%< Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /*%< Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/bitncmp.c b/usr/src/lib/libresolv2_joy/common/isc/bitncmp.c
new file mode 100644
index 0000000000..efe5009292
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/bitncmp.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996, 1999, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: bitncmp.c,v 1.5 2008/11/14 02:36:51 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+
+/*%
+ * int
+ * bitncmp(l, r, n)
+ * compare bit masks l and r, for n bits.
+ * return:
+ * -1, 1, or 0 in the libc tradition.
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0x11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+int
+bitncmp(const void *l, const void *r, int n) {
+ u_int lb, rb;
+ int x, b;
+
+ b = n / 8;
+ x = memcmp(l, r, b);
+ if (x || (n % 8) == 0)
+ return (x);
+
+ lb = ((const u_char *)l)[b];
+ rb = ((const u_char *)r)[b];
+ for (b = n % 8; b > 0; b--) {
+ if ((lb & 0x80) != (rb & 0x80)) {
+ if (lb & 0x80)
+ return (1);
+ return (-1);
+ }
+ lb <<= 1;
+ rb <<= 1;
+ }
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ctl_clnt.c b/usr/src/lib/libresolv2_joy/common/isc/ctl_clnt.c
new file mode 100644
index 0000000000..f71001a6d4
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ctl_clnt.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_clnt.c,v 1.11 2008/11/14 02:36:51 marka Exp $";
+#endif /* not lint */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+
+/* Macros. */
+
+#define donefunc_p(ctx) ((ctx).donefunc != NULL)
+#define arpacode_p(line) (isdigit((unsigned char)(line[0])) && \
+ isdigit((unsigned char)(line[1])) && \
+ isdigit((unsigned char)(line[2])))
+#define arpacont_p(line) (line[3] == '-')
+#define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \
+ line[3] == '\r' || line[3] == '\0')
+
+/* Types. */
+
+enum state {
+ initializing = 0, connecting, connected, destroyed
+};
+
+struct ctl_tran {
+ LINK(struct ctl_tran) link;
+ LINK(struct ctl_tran) wlink;
+ struct ctl_cctx * ctx;
+ struct ctl_buf outbuf;
+ ctl_clntdone donefunc;
+ void * uap;
+};
+
+struct ctl_cctx {
+ enum state state;
+ evContext ev;
+ int sock;
+ ctl_logfunc logger;
+ ctl_clntdone donefunc;
+ void * uap;
+ evConnID coID;
+ evTimerID tiID;
+ evFileID rdID;
+ evStreamID wrID;
+ struct ctl_buf inbuf;
+ struct timespec timeout;
+ LIST(struct ctl_tran) tran;
+ LIST(struct ctl_tran) wtran;
+};
+
+/* Forward. */
+
+static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int);
+static void start_write(struct ctl_cctx *);
+static void destroy(struct ctl_cctx *, int);
+static void error(struct ctl_cctx *);
+static void new_state(struct ctl_cctx *, enum state);
+static void conn_done(evContext, void *, int,
+ const void *, int,
+ const void *, int);
+static void write_done(evContext, void *, int, int);
+static void start_read(struct ctl_cctx *);
+static void stop_read(struct ctl_cctx *);
+static void readable(evContext, void *, int, int);
+static void start_timer(struct ctl_cctx *);
+static void stop_timer(struct ctl_cctx *);
+static void touch_timer(struct ctl_cctx *);
+static void timer(evContext, void *,
+ struct timespec, struct timespec);
+
+#ifndef HAVE_MEMCHR
+static void *
+memchr(const void *b, int c, size_t len) {
+ const unsigned char *p = b;
+ size_t i;
+
+ for (i = 0; i < len; i++, p++)
+ if (*p == (unsigned char)c)
+ return ((void *)p);
+ return (NULL);
+}
+#endif
+
+/* Private data. */
+
+static const char * const state_names[] = {
+ "initializing", "connecting", "connected", "destroyed"
+};
+
+/* Public. */
+
+/*%
+ * void
+ * ctl_client()
+ * create, condition, and connect to a listener on the control port.
+ */
+struct ctl_cctx *
+ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len,
+ const struct sockaddr *sap, size_t sap_len,
+ ctl_clntdone donefunc, void *uap,
+ u_int timeout, ctl_logfunc logger)
+{
+ static const char me[] = "ctl_client";
+ static const int on = 1;
+ struct ctl_cctx *ctx;
+ struct sockaddr *captmp;
+
+ if (logger == NULL)
+ logger = ctl_logger;
+ ctx = memget(sizeof *ctx);
+ if (ctx == NULL) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ goto fatal;
+ }
+ ctx->state = initializing;
+ ctx->ev = lev;
+ ctx->logger = logger;
+ ctx->timeout = evConsTime(timeout, 0);
+ ctx->donefunc = donefunc;
+ ctx->uap = uap;
+ ctx->coID.opaque = NULL;
+ ctx->tiID.opaque = NULL;
+ ctx->rdID.opaque = NULL;
+ ctx->wrID.opaque = NULL;
+ buffer_init(ctx->inbuf);
+ INIT_LIST(ctx->tran);
+ INIT_LIST(ctx->wtran);
+ ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (ctx->sock > evHighestFD(ctx->ev)) {
+ ctx->sock = -1;
+ errno = ENOTSOCK;
+ }
+ if (ctx->sock < 0) {
+ (*ctx->logger)(ctl_error, "%s: socket: %s",
+ me, strerror(errno));
+ goto fatal;
+ }
+ if (cap != NULL) {
+ if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&on, sizeof on) != 0) {
+ (*ctx->logger)(ctl_warning,
+ "%s: setsockopt(REUSEADDR): %s",
+ me, strerror(errno));
+ }
+ DE_CONST(cap, captmp);
+ if (bind(ctx->sock, captmp, cap_len) < 0) {
+ (*ctx->logger)(ctl_error, "%s: bind: %s", me,
+ strerror(errno));
+ goto fatal;
+ }
+ }
+ if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len,
+ conn_done, ctx, &ctx->coID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
+ me, ctx->sock, strerror(errno));
+ fatal:
+ if (ctx != NULL) {
+ if (ctx->sock >= 0)
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ }
+ return (NULL);
+ }
+ new_state(ctx, connecting);
+ return (ctx);
+}
+
+/*%
+ * void
+ * ctl_endclient(ctx)
+ * close a client and release all of its resources.
+ */
+void
+ctl_endclient(struct ctl_cctx *ctx) {
+ if (ctx->state != destroyed)
+ destroy(ctx, 0);
+ memput(ctx, sizeof *ctx);
+}
+
+/*%
+ * int
+ * ctl_command(ctx, cmd, len, donefunc, uap)
+ * Queue a transaction, which will begin with sending cmd
+ * and complete by calling donefunc with the answer.
+ */
+int
+ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len,
+ ctl_clntdone donefunc, void *uap)
+{
+ struct ctl_tran *tran;
+ char *pc;
+ unsigned int n;
+
+ switch (ctx->state) {
+ case destroyed:
+ errno = ENOTCONN;
+ return (-1);
+ case connecting:
+ case connected:
+ break;
+ default:
+ abort();
+ }
+ if (len >= (size_t)MAX_LINELEN) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ tran = new_tran(ctx, donefunc, uap, 1);
+ if (tran == NULL)
+ return (-1);
+ if (ctl_bufget(&tran->outbuf, ctx->logger) < 0)
+ return (-1);
+ memcpy(tran->outbuf.text, cmd, len);
+ tran->outbuf.used = len;
+ for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++)
+ if (!isascii((unsigned char)*pc) ||
+ !isprint((unsigned char)*pc))
+ *pc = '\040';
+ start_write(ctx);
+ return (0);
+}
+
+/* Private. */
+
+static struct ctl_tran *
+new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) {
+ struct ctl_tran *new = memget(sizeof *new);
+
+ if (new == NULL)
+ return (NULL);
+ new->ctx = ctx;
+ buffer_init(new->outbuf);
+ new->donefunc = donefunc;
+ new->uap = uap;
+ INIT_LINK(new, link);
+ INIT_LINK(new, wlink);
+ APPEND(ctx->tran, new, link);
+ if (w)
+ APPEND(ctx->wtran, new, wlink);
+ return (new);
+}
+
+static void
+start_write(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_write";
+ struct ctl_tran *tran;
+ struct iovec iov[2], *iovp = iov;
+ char * tmp;
+
+ REQUIRE(ctx->state == connecting || ctx->state == connected);
+ /* If there is a write in progress, don't try to write more yet. */
+ if (ctx->wrID.opaque != NULL)
+ return;
+ /* If there are no trans, make sure timer is off, and we're done. */
+ if (EMPTY(ctx->wtran)) {
+ if (ctx->tiID.opaque != NULL)
+ stop_timer(ctx);
+ return;
+ }
+ /* Pull it off the head of the write queue. */
+ tran = HEAD(ctx->wtran);
+ UNLINK(ctx->wtran, tran, wlink);
+ /* Since there are some trans, make sure timer is successfully "on". */
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ else
+ start_timer(ctx);
+ if (ctx->state == destroyed)
+ return;
+ /* Marshall a newline-terminated message and clock it out. */
+ *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used);
+ DE_CONST("\r\n", tmp);
+ *iovp++ = evConsIovec(tmp, 2);
+ if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov,
+ write_done, tran, &ctx->wrID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evWrite: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+destroy(struct ctl_cctx *ctx, int notify) {
+ struct ctl_tran *this, *next;
+
+ if (ctx->sock != -1) {
+ (void) close(ctx->sock);
+ ctx->sock = -1;
+ }
+ switch (ctx->state) {
+ case connecting:
+ REQUIRE(ctx->wrID.opaque == NULL);
+ REQUIRE(EMPTY(ctx->tran));
+ /*
+ * This test is nec'y since destroy() can be called from
+ * start_read() while the state is still "connecting".
+ */
+ if (ctx->coID.opaque != NULL) {
+ (void)evCancelConn(ctx->ev, ctx->coID);
+ ctx->coID.opaque = NULL;
+ }
+ break;
+ case connected:
+ REQUIRE(ctx->coID.opaque == NULL);
+ if (ctx->wrID.opaque != NULL) {
+ (void)evCancelRW(ctx->ev, ctx->wrID);
+ ctx->wrID.opaque = NULL;
+ }
+ if (ctx->rdID.opaque != NULL)
+ stop_read(ctx);
+ break;
+ case destroyed:
+ break;
+ default:
+ abort();
+ }
+ if (allocated_p(ctx->inbuf))
+ ctl_bufput(&ctx->inbuf);
+ for (this = HEAD(ctx->tran); this != NULL; this = next) {
+ next = NEXT(this, link);
+ if (allocated_p(this->outbuf))
+ ctl_bufput(&this->outbuf);
+ if (notify && this->donefunc != NULL)
+ (*this->donefunc)(ctx, this->uap, NULL, 0);
+ memput(this, sizeof *this);
+ }
+ if (ctx->tiID.opaque != NULL)
+ stop_timer(ctx);
+ new_state(ctx, destroyed);
+}
+
+static void
+error(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->state != destroyed);
+ destroy(ctx, 1);
+}
+
+static void
+new_state(struct ctl_cctx *ctx, enum state new_state) {
+ static const char me[] = "isc/ctl_clnt::new_state";
+
+ (*ctx->logger)(ctl_debug, "%s: %s -> %s", me,
+ state_names[ctx->state], state_names[new_state]);
+ ctx->state = new_state;
+}
+
+static void
+conn_done(evContext ev, void *uap, int fd,
+ const void *la, int lalen,
+ const void *ra, int ralen)
+{
+ static const char me[] = "isc/ctl_clnt::conn_done";
+ struct ctl_cctx *ctx = uap;
+ struct ctl_tran *tran;
+
+ UNUSED(ev);
+ UNUSED(la);
+ UNUSED(lalen);
+ UNUSED(ra);
+ UNUSED(ralen);
+
+ ctx->coID.opaque = NULL;
+ if (fd < 0) {
+ (*ctx->logger)(ctl_error, "%s: evConnect: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ new_state(ctx, connected);
+ tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0);
+ if (tran == NULL) {
+ (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ start_read(ctx);
+ if (ctx->state == destroyed) {
+ (*ctx->logger)(ctl_error, "%s: start_read failed: %s",
+ me, strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+write_done(evContext lev, void *uap, int fd, int bytes) {
+ struct ctl_tran *tran = (struct ctl_tran *)uap;
+ struct ctl_cctx *ctx = tran->ctx;
+
+ UNUSED(lev);
+ UNUSED(fd);
+
+ ctx->wrID.opaque = NULL;
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ ctl_bufput(&tran->outbuf);
+ start_write(ctx);
+ if (bytes < 0)
+ destroy(ctx, 1);
+ else
+ start_read(ctx);
+}
+
+static void
+start_read(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_read";
+
+ REQUIRE(ctx->state == connecting || ctx->state == connected);
+ REQUIRE(ctx->rdID.opaque == NULL);
+ if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx,
+ &ctx->rdID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me,
+ ctx->sock, strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+stop_read(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->coID.opaque == NULL);
+ REQUIRE(ctx->rdID.opaque != NULL);
+ (void)evDeselectFD(ctx->ev, ctx->rdID);
+ ctx->rdID.opaque = NULL;
+}
+
+static void
+readable(evContext ev, void *uap, int fd, int evmask) {
+ static const char me[] = "isc/ctl_clnt::readable";
+ struct ctl_cctx *ctx = uap;
+ struct ctl_tran *tran;
+ ssize_t n;
+ char *eos;
+
+ UNUSED(ev);
+
+ REQUIRE(ctx != NULL);
+ REQUIRE(fd >= 0);
+ REQUIRE(evmask == EV_READ);
+ REQUIRE(ctx->state == connected);
+ REQUIRE(!EMPTY(ctx->tran));
+ tran = HEAD(ctx->tran);
+ if (!allocated_p(ctx->inbuf) &&
+ ctl_bufget(&ctx->inbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me);
+ error(ctx);
+ return;
+ }
+ n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used,
+ MAX_LINELEN - ctx->inbuf.used);
+ if (n <= 0) {
+ (*ctx->logger)(ctl_warning, "%s: read: %s", me,
+ (n == 0) ? "Unexpected EOF" : strerror(errno));
+ error(ctx);
+ return;
+ }
+ if (ctx->tiID.opaque != NULL)
+ touch_timer(ctx);
+ ctx->inbuf.used += n;
+ (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me,
+ n, ctx->inbuf.used);
+ again:
+ eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used);
+ if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') {
+ int done = 0;
+
+ eos[-1] = '\0';
+ if (!arpacode_p(ctx->inbuf.text)) {
+ /* XXX Doesn't FTP do this sometimes? Is it legal? */
+ (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ return;
+ }
+ if (arpadone_p(ctx->inbuf.text))
+ done = 1;
+ else if (arpacont_p(ctx->inbuf.text))
+ done = 0;
+ else {
+ /* XXX Doesn't FTP do this sometimes? Is it legal? */
+ (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ return;
+ }
+ (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text,
+ (done ? 0 : CTL_MORE));
+ ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1);
+ if (ctx->inbuf.used == 0U)
+ ctl_bufput(&ctx->inbuf);
+ else
+ memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used);
+ if (done) {
+ UNLINK(ctx->tran, tran, link);
+ memput(tran, sizeof *tran);
+ stop_read(ctx);
+ start_write(ctx);
+ return;
+ }
+ if (allocated_p(ctx->inbuf))
+ goto again;
+ return;
+ }
+ if (ctx->inbuf.used == (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me,
+ ctx->inbuf.text);
+ error(ctx);
+ }
+}
+
+/* Timer related stuff. */
+
+static void
+start_timer(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::start_timer";
+
+ REQUIRE(ctx->tiID.opaque == NULL);
+ if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){
+ (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+}
+
+static void
+stop_timer(struct ctl_cctx *ctx) {
+ static const char me[] = "isc/ctl_clnt::stop_timer";
+
+ REQUIRE(ctx->tiID.opaque != NULL);
+ if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me,
+ strerror(errno));
+ error(ctx);
+ return;
+ }
+ ctx->tiID.opaque = NULL;
+}
+
+static void
+touch_timer(struct ctl_cctx *ctx) {
+ REQUIRE(ctx->tiID.opaque != NULL);
+
+ evTouchIdleTimer(ctx->ev, ctx->tiID);
+}
+
+static void
+timer(evContext ev, void *uap, struct timespec due, struct timespec itv) {
+ static const char me[] = "isc/ctl_clnt::timer";
+ struct ctl_cctx *ctx = uap;
+
+ UNUSED(ev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ ctx->tiID.opaque = NULL;
+ (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me,
+ ctx->timeout.tv_sec, state_names[ctx->state]);
+ error(ctx);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ctl_p.c b/usr/src/lib/libresolv2_joy/common/isc/ctl_p.c
new file mode 100644
index 0000000000..7ab719a5e6
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ctl_p.c
@@ -0,0 +1,188 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_p.c,v 1.4 2005/04/27 04:56:35 sra Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/ctl.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+const char * const ctl_sevnames[] = {
+ "debug", "warning", "error"
+};
+
+/* Public. */
+
+/*%
+ * ctl_logger()
+ * if ctl_startup()'s caller didn't specify a logger, this one
+ * is used. this pollutes stderr with all kinds of trash so it will
+ * probably never be used in real applications.
+ */
+void
+ctl_logger(enum ctl_severity severity, const char *format, ...) {
+ va_list ap;
+ static const char me[] = "ctl_logger";
+
+ fprintf(stderr, "%s(%s): ", me, ctl_sevnames[severity]);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+int
+ctl_bufget(struct ctl_buf *buf, ctl_logfunc logger) {
+ static const char me[] = "ctl_bufget";
+
+ REQUIRE(!allocated_p(*buf) && buf->used == 0U);
+ buf->text = memget(MAX_LINELEN);
+ if (!allocated_p(*buf)) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ return (-1);
+ }
+ buf->used = 0;
+ return (0);
+}
+
+void
+ctl_bufput(struct ctl_buf *buf) {
+
+ REQUIRE(allocated_p(*buf));
+ memput(buf->text, MAX_LINELEN);
+ buf->text = NULL;
+ buf->used = 0;
+}
+
+const char *
+ctl_sa_ntop(const struct sockaddr *sa,
+ char *buf, size_t size,
+ ctl_logfunc logger)
+{
+ static const char me[] = "ctl_sa_ntop";
+ static const char punt[] = "[0].-1";
+ char tmp[INET6_ADDRSTRLEN];
+
+ switch (sa->sa_family) {
+ case AF_INET6: {
+ const struct sockaddr_in6 *in6 =
+ (const struct sockaddr_in6 *) sa;
+
+ if (inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp, sizeof tmp)
+ == NULL) {
+ (*logger)(ctl_error, "%s: inet_ntop(%u %04x): %s",
+ me, in6->sin6_family,
+ in6->sin6_port, strerror(errno));
+ return (punt);
+ }
+ if (strlen(tmp) + sizeof "[].65535" > size) {
+ (*logger)(ctl_error, "%s: buffer overflow", me);
+ return (punt);
+ }
+ (void) sprintf(buf, "[%s].%u", tmp, ntohs(in6->sin6_port));
+ return (buf);
+ }
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *) sa;
+
+ if (inet_ntop(in->sin_family, &in->sin_addr, tmp, sizeof tmp)
+ == NULL) {
+ (*logger)(ctl_error, "%s: inet_ntop(%u %04x %08x): %s",
+ me, in->sin_family,
+ in->sin_port, in->sin_addr.s_addr,
+ strerror(errno));
+ return (punt);
+ }
+ if (strlen(tmp) + sizeof "[].65535" > size) {
+ (*logger)(ctl_error, "%s: buffer overflow", me);
+ return (punt);
+ }
+ (void) sprintf(buf, "[%s].%u", tmp, ntohs(in->sin_port));
+ return (buf);
+ }
+#ifndef NO_SOCKADDR_UN
+ case AF_UNIX: {
+ const struct sockaddr_un *un =
+ (const struct sockaddr_un *) sa;
+ unsigned int x = sizeof un->sun_path;
+
+ if (x > size)
+ x = size;
+ strncpy(buf, un->sun_path, x - 1);
+ buf[x - 1] = '\0';
+ return (buf);
+ }
+#endif
+ default:
+ return (punt);
+ }
+}
+
+void
+ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) {
+ switch (src->sa_family) {
+ case AF_INET6:
+ *((struct sockaddr_in6 *)dst) =
+ *((const struct sockaddr_in6 *)src);
+ break;
+ case AF_INET:
+ *((struct sockaddr_in *)dst) =
+ *((const struct sockaddr_in *)src);
+ break;
+#ifndef NO_SOCKADDR_UN
+ case AF_UNIX:
+ *((struct sockaddr_un *)dst) =
+ *((const struct sockaddr_un *)src);
+ break;
+#endif
+ default:
+ *dst = *src;
+ break;
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ctl_p.h b/usr/src/lib/libresolv2_joy/common/isc/ctl_p.h
new file mode 100644
index 0000000000..18a52ae39c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ctl_p.h
@@ -0,0 +1,28 @@
+struct ctl_buf {
+ char * text;
+ size_t used;
+};
+
+#define MAX_LINELEN 990 /*%< Like SMTP. */
+#ifndef NO_SOCKADDR_UN
+#define MAX_NTOP PATH_MAX
+#else
+#define MAX_NTOP (sizeof "[255.255.255.255].65535")
+#endif
+
+#define allocated_p(Buf) ((Buf).text != NULL)
+#define buffer_init(Buf) ((Buf).text = 0, (Buf.used) = 0)
+
+#define ctl_bufget __ctl_bufget
+#define ctl_bufput __ctl_bufput
+#define ctl_sa_ntop __ctl_sa_ntop
+#define ctl_sa_copy __ctl_sa_copy
+
+int ctl_bufget(struct ctl_buf *, ctl_logfunc);
+void ctl_bufput(struct ctl_buf *);
+const char * ctl_sa_ntop(const struct sockaddr *, char *, size_t,
+ ctl_logfunc);
+void ctl_sa_copy(const struct sockaddr *,
+ struct sockaddr *);
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ctl_srvr.c b/usr/src/lib/libresolv2_joy/common/isc/ctl_srvr.c
new file mode 100644
index 0000000000..8fd7a21ffa
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ctl_srvr.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_srvr.c,v 1.10 2008/11/14 02:36:51 marka Exp $";
+#endif /* not lint */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Macros. */
+
+#define lastverb_p(verb) (verb->name == NULL || verb->func == NULL)
+#define address_expr ctl_sa_ntop((struct sockaddr *)&sess->sa, \
+ tmp, sizeof tmp, ctx->logger)
+
+/* Types. */
+
+enum state {
+ available = 0, initializing, writing, reading, reading_data,
+ processing, idling, quitting, closing
+};
+
+union sa_un {
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+};
+
+struct ctl_sess {
+ LINK(struct ctl_sess) link;
+ struct ctl_sctx * ctx;
+ enum state state;
+ int sock;
+ union sa_un sa;
+ evFileID rdID;
+ evStreamID wrID;
+ evTimerID rdtiID;
+ evTimerID wrtiID;
+ struct ctl_buf inbuf;
+ struct ctl_buf outbuf;
+ const struct ctl_verb * verb;
+ u_int helpcode;
+ const void * respctx;
+ u_int respflags;
+ ctl_srvrdone donefunc;
+ void * uap;
+ void * csctx;
+};
+
+struct ctl_sctx {
+ evContext ev;
+ void * uctx;
+ u_int unkncode;
+ u_int timeoutcode;
+ const struct ctl_verb * verbs;
+ const struct ctl_verb * connverb;
+ int sock;
+ int max_sess;
+ int cur_sess;
+ struct timespec timeout;
+ ctl_logfunc logger;
+ evConnID acID;
+ LIST(struct ctl_sess) sess;
+};
+
+/* Forward. */
+
+static void ctl_accept(evContext, void *, int,
+ const void *, int,
+ const void *, int);
+static void ctl_close(struct ctl_sess *);
+static void ctl_new_state(struct ctl_sess *,
+ enum state,
+ const char *);
+static void ctl_start_read(struct ctl_sess *);
+static void ctl_stop_read(struct ctl_sess *);
+static void ctl_readable(evContext, void *, int, int);
+static void ctl_rdtimeout(evContext, void *,
+ struct timespec,
+ struct timespec);
+static void ctl_wrtimeout(evContext, void *,
+ struct timespec,
+ struct timespec);
+static void ctl_docommand(struct ctl_sess *);
+static void ctl_writedone(evContext, void *, int, int);
+static void ctl_morehelp(struct ctl_sctx *,
+ struct ctl_sess *,
+ const struct ctl_verb *,
+ const char *,
+ u_int, const void *, void *);
+static void ctl_signal_done(struct ctl_sctx *,
+ struct ctl_sess *);
+
+/* Private data. */
+
+static const char * state_names[] = {
+ "available", "initializing", "writing", "reading",
+ "reading_data", "processing", "idling", "quitting", "closing"
+};
+
+static const char space[] = " ";
+
+static const struct ctl_verb fakehelpverb = {
+ "fakehelp", ctl_morehelp , NULL
+};
+
+/* Public. */
+
+/*%
+ * void
+ * ctl_server()
+ * create, condition, and start a listener on the control port.
+ */
+struct ctl_sctx *
+ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len,
+ const struct ctl_verb *verbs,
+ u_int unkncode, u_int timeoutcode,
+ u_int timeout, int backlog, int max_sess,
+ ctl_logfunc logger, void *uctx)
+{
+ static const char me[] = "ctl_server";
+ static const int on = 1;
+ const struct ctl_verb *connverb;
+ struct ctl_sctx *ctx;
+ int save_errno;
+
+ if (logger == NULL)
+ logger = ctl_logger;
+ for (connverb = verbs;
+ connverb->name != NULL && connverb->func != NULL;
+ connverb++)
+ if (connverb->name[0] == '\0')
+ break;
+ if (connverb->func == NULL) {
+ (*logger)(ctl_error, "%s: no connection verb found", me);
+ return (NULL);
+ }
+ ctx = memget(sizeof *ctx);
+ if (ctx == NULL) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ return (NULL);
+ }
+ ctx->ev = lev;
+ ctx->uctx = uctx;
+ ctx->unkncode = unkncode;
+ ctx->timeoutcode = timeoutcode;
+ ctx->verbs = verbs;
+ ctx->timeout = evConsTime(timeout, 0);
+ ctx->logger = logger;
+ ctx->connverb = connverb;
+ ctx->max_sess = max_sess;
+ ctx->cur_sess = 0;
+ INIT_LIST(ctx->sess);
+ ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+ if (ctx->sock > evHighestFD(ctx->ev)) {
+ ctx->sock = -1;
+ errno = ENOTSOCK;
+ }
+ if (ctx->sock < 0) {
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: socket: %s",
+ me, strerror(errno));
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ if (ctx->sock > evHighestFD(lev)) {
+ close(ctx->sock);
+ (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD");
+ errno = ENFILE;
+ memput(ctx, sizeof *ctx);
+ return (NULL);
+ }
+#ifdef NO_UNIX_REUSEADDR
+ if (sap->sa_family != AF_UNIX)
+#endif
+ if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&on, sizeof on) != 0) {
+ (*ctx->logger)(ctl_warning,
+ "%s: setsockopt(REUSEADDR): %s",
+ me, strerror(errno));
+ }
+ if (bind(ctx->sock, sap, sap_len) < 0) {
+ char tmp[MAX_NTOP];
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: bind: %s: %s",
+ me, ctl_sa_ntop((const struct sockaddr *)sap,
+ tmp, sizeof tmp, ctx->logger),
+ strerror(save_errno));
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ if (fcntl(ctx->sock, F_SETFD, 1) < 0) {
+ (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+ strerror(errno));
+ }
+ if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx,
+ &ctx->acID) < 0) {
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s",
+ me, ctx->sock, strerror(errno));
+ close(ctx->sock);
+ memput(ctx, sizeof *ctx);
+ errno = save_errno;
+ return (NULL);
+ }
+ (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d",
+ me, ctx, ctx->sock);
+ return (ctx);
+}
+
+/*%
+ * void
+ * ctl_endserver(ctx)
+ * if the control listener is open, close it. clean out all eventlib
+ * stuff. close all active sessions.
+ */
+void
+ctl_endserver(struct ctl_sctx *ctx) {
+ static const char me[] = "ctl_endserver";
+ struct ctl_sess *this, *next;
+
+ (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p",
+ me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess);
+ if (ctx->acID.opaque != NULL) {
+ (void)evCancelConn(ctx->ev, ctx->acID);
+ ctx->acID.opaque = NULL;
+ }
+ if (ctx->sock != -1) {
+ (void) close(ctx->sock);
+ ctx->sock = -1;
+ }
+ for (this = HEAD(ctx->sess); this != NULL; this = next) {
+ next = NEXT(this, link);
+ ctl_close(this);
+ }
+ memput(ctx, sizeof *ctx);
+}
+
+/*%
+ * If body is non-NULL then it we add a "." line after it.
+ * Caller must have escaped lines with leading ".".
+ */
+void
+ctl_response(struct ctl_sess *sess, u_int code, const char *text,
+ u_int flags, const void *respctx, ctl_srvrdone donefunc,
+ void *uap, const char *body, size_t bodylen)
+{
+ static const char me[] = "ctl_response";
+ struct iovec iov[3], *iovp = iov;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP], *pc;
+ int n;
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == processing ||
+ sess->state == reading_data ||
+ sess->state == writing);
+ REQUIRE(sess->wrtiID.opaque == NULL);
+ REQUIRE(sess->wrID.opaque == NULL);
+ ctl_new_state(sess, writing, me);
+ sess->donefunc = donefunc;
+ sess->uap = uap;
+ if (!allocated_p(sess->outbuf) &&
+ ctl_bufget(&sess->outbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer",
+ me, address_expr);
+ goto untimely;
+ }
+ if (sizeof "000-\r\n" + strlen(text) > (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing",
+ me, address_expr);
+ goto untimely;
+ }
+ sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n",
+ code, (flags & CTL_MORE) != 0 ? '-' : ' ',
+ text));
+ for (pc = sess->outbuf.text, n = 0;
+ n < (int)sess->outbuf.used-2; pc++, n++)
+ if (!isascii((unsigned char)*pc) ||
+ !isprint((unsigned char)*pc))
+ *pc = '\040';
+ *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used);
+ if (body != NULL) {
+ char *tmp;
+ DE_CONST(body, tmp);
+ *iovp++ = evConsIovec(tmp, bodylen);
+ DE_CONST(".\r\n", tmp);
+ *iovp++ = evConsIovec(tmp, 3);
+ }
+ (*ctx->logger)(ctl_debug, "%s: [%d] %s", me,
+ sess->outbuf.used, sess->outbuf.text);
+ if (evWrite(ctx->ev, sess->sock, iov, iovp - iov,
+ ctl_writedone, sess, &sess->wrID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me,
+ address_expr, strerror(errno));
+ goto untimely;
+ }
+ if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout,
+ &sess->wrtiID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+ address_expr, strerror(errno));
+ goto untimely;
+ }
+ if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me,
+ address_expr, strerror(errno));
+ untimely:
+ ctl_signal_done(ctx, sess);
+ ctl_close(sess);
+ return;
+ }
+ sess->respctx = respctx;
+ sess->respflags = flags;
+}
+
+void
+ctl_sendhelp(struct ctl_sess *sess, u_int code) {
+ static const char me[] = "ctl_sendhelp";
+ struct ctl_sctx *ctx = sess->ctx;
+
+ sess->helpcode = code;
+ sess->verb = &fakehelpverb;
+ ctl_morehelp(ctx, sess, NULL, me, CTL_MORE,
+ (const void *)ctx->verbs, NULL);
+}
+
+void *
+ctl_getcsctx(struct ctl_sess *sess) {
+ return (sess->csctx);
+}
+
+void *
+ctl_setcsctx(struct ctl_sess *sess, void *csctx) {
+ void *old = sess->csctx;
+
+ sess->csctx = csctx;
+ return (old);
+}
+
+/* Private functions. */
+
+static void
+ctl_accept(evContext lev, void *uap, int fd,
+ const void *lav, int lalen,
+ const void *rav, int ralen)
+{
+ static const char me[] = "ctl_accept";
+ struct ctl_sctx *ctx = uap;
+ struct ctl_sess *sess = NULL;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(lalen);
+ UNUSED(ralen);
+
+ if (fd < 0) {
+ (*ctx->logger)(ctl_error, "%s: accept: %s",
+ me, strerror(errno));
+ return;
+ }
+ if (ctx->cur_sess == ctx->max_sess) {
+ (*ctx->logger)(ctl_error, "%s: %s: too many control sessions",
+ me, ctl_sa_ntop((const struct sockaddr *)rav,
+ tmp, sizeof tmp,
+ ctx->logger));
+ (void) close(fd);
+ return;
+ }
+ sess = memget(sizeof *sess);
+ if (sess == NULL) {
+ (*ctx->logger)(ctl_error, "%s: memget: %s", me,
+ strerror(errno));
+ (void) close(fd);
+ return;
+ }
+ if (fcntl(fd, F_SETFD, 1) < 0) {
+ (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+ strerror(errno));
+ }
+ ctx->cur_sess++;
+ INIT_LINK(sess, link);
+ APPEND(ctx->sess, sess, link);
+ sess->ctx = ctx;
+ sess->sock = fd;
+ sess->wrID.opaque = NULL;
+ sess->rdID.opaque = NULL;
+ sess->wrtiID.opaque = NULL;
+ sess->rdtiID.opaque = NULL;
+ sess->respctx = NULL;
+ sess->csctx = NULL;
+ if (((const struct sockaddr *)rav)->sa_family == AF_UNIX)
+ ctl_sa_copy((const struct sockaddr *)lav,
+ (struct sockaddr *)&sess->sa);
+ else
+ ctl_sa_copy((const struct sockaddr *)rav,
+ (struct sockaddr *)&sess->sa);
+ sess->donefunc = NULL;
+ buffer_init(sess->inbuf);
+ buffer_init(sess->outbuf);
+ sess->state = available;
+ ctl_new_state(sess, initializing, me);
+ sess->verb = ctx->connverb;
+ (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)",
+ me, address_expr, sess->sock);
+ (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0,
+ (const struct sockaddr *)rav, ctx->uctx);
+}
+
+static void
+ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason)
+{
+ static const char me[] = "ctl_new_state";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)",
+ me, address_expr,
+ state_names[sess->state],
+ state_names[new_state], reason);
+ sess->state = new_state;
+}
+
+static void
+ctl_close(struct ctl_sess *sess) {
+ static const char me[] = "ctl_close";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == writing ||
+ sess->state == reading ||
+ sess->state == processing ||
+ sess->state == reading_data ||
+ sess->state == idling);
+ REQUIRE(sess->sock != -1);
+ if (sess->state == reading || sess->state == reading_data)
+ ctl_stop_read(sess);
+ else if (sess->state == writing) {
+ if (sess->wrID.opaque != NULL) {
+ (void) evCancelRW(ctx->ev, sess->wrID);
+ sess->wrID.opaque = NULL;
+ }
+ if (sess->wrtiID.opaque != NULL) {
+ (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+ sess->wrtiID.opaque = NULL;
+ }
+ }
+ ctl_new_state(sess, closing, me);
+ (void) close(sess->sock);
+ if (allocated_p(sess->inbuf))
+ ctl_bufput(&sess->inbuf);
+ if (allocated_p(sess->outbuf))
+ ctl_bufput(&sess->outbuf);
+ (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)",
+ me, address_expr, sess->sock);
+ UNLINK(ctx->sess, sess, link);
+ memput(sess, sizeof *sess);
+ ctx->cur_sess--;
+}
+
+static void
+ctl_start_read(struct ctl_sess *sess) {
+ static const char me[] = "ctl_start_read";
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ REQUIRE(sess->state == initializing ||
+ sess->state == writing ||
+ sess->state == processing ||
+ sess->state == idling);
+ REQUIRE(sess->rdtiID.opaque == NULL);
+ REQUIRE(sess->rdID.opaque == NULL);
+ sess->inbuf.used = 0;
+ if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout,
+ &sess->rdtiID) < 0)
+ {
+ (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+ address_expr, strerror(errno));
+ ctl_close(sess);
+ return;
+ }
+ if (evSelectFD(ctx->ev, sess->sock, EV_READ,
+ ctl_readable, sess, &sess->rdID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me,
+ address_expr, strerror(errno));
+ return;
+ }
+ ctl_new_state(sess, reading, me);
+}
+
+static void
+ctl_stop_read(struct ctl_sess *sess) {
+ static const char me[] = "ctl_stop_read";
+ struct ctl_sctx *ctx = sess->ctx;
+
+ REQUIRE(sess->state == reading || sess->state == reading_data);
+ REQUIRE(sess->rdID.opaque != NULL);
+ (void) evDeselectFD(ctx->ev, sess->rdID);
+ sess->rdID.opaque = NULL;
+ if (sess->rdtiID.opaque != NULL) {
+ (void) evClearIdleTimer(ctx->ev, sess->rdtiID);
+ sess->rdtiID.opaque = NULL;
+ }
+ ctl_new_state(sess, idling, me);
+}
+
+static void
+ctl_readable(evContext lev, void *uap, int fd, int evmask) {
+ static const char me[] = "ctl_readable";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx;
+ char *eos, tmp[MAX_NTOP];
+ ssize_t n;
+
+ REQUIRE(sess != NULL);
+ REQUIRE(fd >= 0);
+ REQUIRE(evmask == EV_READ);
+ REQUIRE(sess->state == reading || sess->state == reading_data);
+
+ ctx = sess->ctx;
+ evTouchIdleTimer(lev, sess->rdtiID);
+ if (!allocated_p(sess->inbuf) &&
+ ctl_bufget(&sess->inbuf, ctx->logger) < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer",
+ me, address_expr);
+ ctl_close(sess);
+ return;
+ }
+ n = read(sess->sock, sess->inbuf.text + sess->inbuf.used,
+ MAX_LINELEN - sess->inbuf.used);
+ if (n <= 0) {
+ (*ctx->logger)(ctl_debug, "%s: %s: read: %s",
+ me, address_expr,
+ (n == 0) ? "Unexpected EOF" : strerror(errno));
+ ctl_close(sess);
+ return;
+ }
+ sess->inbuf.used += n;
+ eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used);
+ if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') {
+ eos[-1] = '\0';
+ if ((sess->respflags & CTL_DATA) != 0) {
+ INSIST(sess->verb != NULL);
+ (*sess->verb->func)(sess->ctx, sess, sess->verb,
+ sess->inbuf.text,
+ CTL_DATA, sess->respctx,
+ sess->ctx->uctx);
+ } else {
+ ctl_stop_read(sess);
+ ctl_docommand(sess);
+ }
+ sess->inbuf.used -= ((eos - sess->inbuf.text) + 1);
+ if (sess->inbuf.used == 0U)
+ ctl_bufput(&sess->inbuf);
+ else
+ memmove(sess->inbuf.text, eos + 1, sess->inbuf.used);
+ return;
+ }
+ if (sess->inbuf.used == (size_t)MAX_LINELEN) {
+ (*ctx->logger)(ctl_error, "%s: %s: line too long, closing",
+ me, address_expr);
+ ctl_close(sess);
+ }
+}
+
+static void
+ctl_wrtimeout(evContext lev, void *uap,
+ struct timespec due,
+ struct timespec itv)
+{
+ static const char me[] = "ctl_wrtimeout";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ REQUIRE(sess->state == writing);
+ sess->wrtiID.opaque = NULL;
+ (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing",
+ me, address_expr);
+ if (sess->wrID.opaque != NULL) {
+ (void) evCancelRW(ctx->ev, sess->wrID);
+ sess->wrID.opaque = NULL;
+ }
+ ctl_signal_done(ctx, sess);
+ ctl_new_state(sess, processing, me);
+ ctl_close(sess);
+}
+
+static void
+ctl_rdtimeout(evContext lev, void *uap,
+ struct timespec due,
+ struct timespec itv)
+{
+ static const char me[] = "ctl_rdtimeout";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+
+ UNUSED(lev);
+ UNUSED(due);
+ UNUSED(itv);
+
+ REQUIRE(sess->state == reading);
+ sess->rdtiID.opaque = NULL;
+ (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing",
+ me, address_expr);
+ if (sess->state == reading || sess->state == reading_data)
+ ctl_stop_read(sess);
+ ctl_signal_done(ctx, sess);
+ ctl_new_state(sess, processing, me);
+ ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL,
+ NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_docommand(struct ctl_sess *sess) {
+ static const char me[] = "ctl_docommand";
+ char *name, *rest, tmp[MAX_NTOP];
+ struct ctl_sctx *ctx = sess->ctx;
+ const struct ctl_verb *verb;
+
+ REQUIRE(allocated_p(sess->inbuf));
+ (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]",
+ me, address_expr,
+ sess->inbuf.text, (u_int)sess->inbuf.used);
+ ctl_new_state(sess, processing, me);
+ name = sess->inbuf.text + strspn(sess->inbuf.text, space);
+ rest = name + strcspn(name, space);
+ if (*rest != '\0') {
+ *rest++ = '\0';
+ rest += strspn(rest, space);
+ }
+ for (verb = ctx->verbs;
+ verb != NULL && verb->name != NULL && verb->func != NULL;
+ verb++)
+ if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0)
+ break;
+ if (verb != NULL && verb->name != NULL && verb->func != NULL) {
+ sess->verb = verb;
+ (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx);
+ } else {
+ char buf[1100];
+
+ if (sizeof "Unrecognized command \"\" (args \"\")" +
+ strlen(name) + strlen(rest) > sizeof buf)
+ strcpy(buf, "Unrecognized command (buf ovf)");
+ else
+ sprintf(buf,
+ "Unrecognized command \"%s\" (args \"%s\")",
+ name, rest);
+ ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL,
+ NULL, 0);
+ }
+}
+
+static void
+ctl_writedone(evContext lev, void *uap, int fd, int bytes) {
+ static const char me[] = "ctl_writedone";
+ struct ctl_sess *sess = uap;
+ struct ctl_sctx *ctx = sess->ctx;
+ char tmp[MAX_NTOP];
+ int save_errno = errno;
+
+ UNUSED(lev);
+ UNUSED(uap);
+
+ REQUIRE(sess->state == writing);
+ REQUIRE(fd == sess->sock);
+ REQUIRE(sess->wrtiID.opaque != NULL);
+ sess->wrID.opaque = NULL;
+ (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+ sess->wrtiID.opaque = NULL;
+ if (bytes < 0) {
+ (*ctx->logger)(ctl_error, "%s: %s: %s",
+ me, address_expr, strerror(save_errno));
+ ctl_close(sess);
+ return;
+ }
+
+ INSIST(allocated_p(sess->outbuf));
+ ctl_bufput(&sess->outbuf);
+ if ((sess->respflags & CTL_EXIT) != 0) {
+ ctl_signal_done(ctx, sess);
+ ctl_close(sess);
+ return;
+ } else if ((sess->respflags & CTL_MORE) != 0) {
+ INSIST(sess->verb != NULL);
+ (*sess->verb->func)(sess->ctx, sess, sess->verb, "",
+ CTL_MORE, sess->respctx, sess->ctx->uctx);
+ } else {
+ ctl_signal_done(ctx, sess);
+ ctl_start_read(sess);
+ }
+}
+
+static void
+ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *text,
+ u_int respflags, const void *respctx, void *uctx)
+{
+ const struct ctl_verb *this = respctx, *next = this + 1;
+
+ UNUSED(ctx);
+ UNUSED(verb);
+ UNUSED(text);
+ UNUSED(uctx);
+
+ REQUIRE(!lastverb_p(this));
+ REQUIRE((respflags & CTL_MORE) != 0);
+ if (lastverb_p(next))
+ respflags &= ~CTL_MORE;
+ ctl_response(sess, sess->helpcode, this->help, respflags, next,
+ NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) {
+ if (sess->donefunc != NULL) {
+ (*sess->donefunc)(ctx, sess, sess->uap);
+ sess->donefunc = NULL;
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ev_connects.c b/usr/src/lib/libresolv2_joy/common/isc/ev_connects.c
new file mode 100644
index 0000000000..38dfdbe512
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ev_connects.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_connects.c - implement asynch connect/accept for the eventlib
+ * vix 16sep96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_connects.c,v 1.8 2006/03/09 23:57:56 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Macros. */
+
+#define GETXXXNAME(f, s, sa, len) ( \
+ (f((s), (&sa), (&len)) >= 0) ? 0 : \
+ (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
+ memset(&(sa), 0, sizeof (sa)), \
+ (len) = sizeof (sa), \
+ (sa).sa_family = AF_UNIX, \
+ 0 \
+ ) \
+ )
+
+/* Forward. */
+
+static void listener(evContext ctx, void *uap, int fd, int evmask);
+static void connector(evContext ctx, void *uap, int fd, int evmask);
+
+/* Public. */
+
+int
+evListen(evContext opaqueCtx, int fd, int maxconn,
+ evConnFunc func, void *uap, evConnID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *new;
+ int mode;
+
+ OKNEW(new);
+ new->flags = EV_CONN_LISTEN;
+ OKFREE(mode = fcntl(fd, F_GETFL, NULL), new); /*%< side effect: validate fd. */
+ /*
+ * Remember the nonblocking status. We assume that either evSelectFD
+ * has not been done to this fd, or that if it has then the caller
+ * will evCancelConn before they evDeselectFD. If our assumptions
+ * are not met, then we might restore the old nonblocking status
+ * incorrectly.
+ */
+ if ((mode & PORT_NONBLOCK) == 0) {
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+ OKFREE(ioctl(fd, FIONBIO, (char *)&on), new);
+#else
+ OKFREE(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK), new);
+#endif
+ new->flags |= EV_CONN_BLOCK;
+ }
+ OKFREE(listen(fd, maxconn), new);
+ if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){
+ int save = errno;
+
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ new->flags |= EV_CONN_SELECTED;
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ if (ctx->conns != NULL)
+ ctx->conns->prev = new;
+ new->prev = NULL;
+ new->next = ctx->conns;
+ ctx->conns = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+}
+
+int
+evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen,
+ evConnFunc func, void *uap, evConnID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *new;
+
+ OKNEW(new);
+ new->flags = 0;
+ /* Do the select() first to get the socket into nonblocking mode. */
+ if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL,
+ connector, new, &new->file) < 0) {
+ int save = errno;
+
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ new->flags |= EV_CONN_SELECTED;
+ if (connect(fd, ra, ralen) < 0 &&
+ errno != EWOULDBLOCK &&
+ errno != EAGAIN &&
+ errno != EINPROGRESS) {
+ int save = errno;
+
+ (void) evDeselectFD(opaqueCtx, new->file);
+ FREE(new);
+ errno = save;
+ return (-1);
+ }
+ /* No error, or EWOULDBLOCK. select() tells when it's ready. */
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ if (ctx->conns != NULL)
+ ctx->conns->prev = new;
+ new->prev = NULL;
+ new->next = ctx->conns;
+ ctx->conns = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+}
+
+int
+evCancelConn(evContext opaqueCtx, evConnID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *this = id.opaque;
+ evAccept *acc, *nxtacc;
+ int mode;
+
+ if ((this->flags & EV_CONN_SELECTED) != 0)
+ (void) evDeselectFD(opaqueCtx, this->file);
+ if ((this->flags & EV_CONN_BLOCK) != 0) {
+ mode = fcntl(this->fd, F_GETFL, NULL);
+ if (mode == -1) {
+ if (errno != EBADF)
+ return (-1);
+ } else {
+#ifdef USE_FIONBIO_IOCTL
+ int off = 0;
+ OK(ioctl(this->fd, FIONBIO, (char *)&off));
+#else
+ OK(fcntl(this->fd, F_SETFL, mode & ~PORT_NONBLOCK));
+#endif
+ }
+ }
+
+ /* Unlink from ctx->conns. */
+ if (this->prev != NULL)
+ this->prev->next = this->next;
+ else
+ ctx->conns = this->next;
+ if (this->next != NULL)
+ this->next->prev = this->prev;
+
+ /*
+ * Remove `this' from the ctx->accepts list (zero or more times).
+ */
+ for (acc = HEAD(ctx->accepts), nxtacc = NULL;
+ acc != NULL;
+ acc = nxtacc)
+ {
+ nxtacc = NEXT(acc, link);
+ if (acc->conn == this) {
+ UNLINK(ctx->accepts, acc, link);
+ close(acc->fd);
+ FREE(acc);
+ }
+ }
+
+ /* Wrap up and get out. */
+ FREE(this);
+ return (0);
+}
+
+int evHold(evContext opaqueCtx, evConnID id) {
+ evConn *this = id.opaque;
+
+ if ((this->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((this->flags & EV_CONN_SELECTED) == 0)
+ return (0);
+ this->flags &= ~EV_CONN_SELECTED;
+ return (evDeselectFD(opaqueCtx, this->file));
+}
+
+int evUnhold(evContext opaqueCtx, evConnID id) {
+ evConn *this = id.opaque;
+ int ret;
+
+ if ((this->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((this->flags & EV_CONN_SELECTED) != 0)
+ return (0);
+ ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this,
+ &this->file);
+ if (ret == 0)
+ this->flags |= EV_CONN_SELECTED;
+ return (ret);
+}
+
+int
+evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *conn = id.opaque;
+ evAccept *new;
+
+ if ((conn->flags & EV_CONN_LISTEN) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ OKNEW(new);
+ new->conn = conn;
+ new->ralen = sizeof new->ra;
+ new->fd = accept(conn->fd, &new->ra.sa, &new->ralen);
+ if (new->fd > ctx->highestFD) {
+ close(new->fd);
+ new->fd = -1;
+ new->ioErrno = ENOTSOCK;
+ }
+ if (new->fd >= 0) {
+ new->lalen = sizeof new->la;
+ if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) {
+ new->ioErrno = errno;
+ (void) close(new->fd);
+ new->fd = -1;
+ } else
+ new->ioErrno = 0;
+ } else {
+ new->ioErrno = errno;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ FREE(new);
+ return (-1);
+ }
+ }
+ INIT_LINK(new, link);
+ APPEND(ctx->accepts, new, link);
+ *sys_errno = new->ioErrno;
+ return (0);
+}
+
+/* Private. */
+
+static void
+listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evConn *conn = uap;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la, ra;
+ int new;
+ ISC_SOCKLEN_T lalen = 0, ralen;
+
+ REQUIRE((evmask & EV_READ) != 0);
+ ralen = sizeof ra;
+ new = accept(fd, &ra.sa, &ralen);
+ if (new > ctx->highestFD) {
+ close(new);
+ new = -1;
+ errno = ENOTSOCK;
+ }
+ if (new >= 0) {
+ lalen = sizeof la;
+ if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) {
+ int save = errno;
+
+ (void) close(new);
+ errno = save;
+ new = -1;
+ }
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+ (*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen);
+}
+
+static void
+connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evConn *conn = uap;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la, ra;
+ ISC_SOCKLEN_T lalen, ralen;
+#ifndef NETREAD_BROKEN
+ char buf[1];
+#endif
+ void *conn_uap;
+ evConnFunc conn_func;
+ evConnID id;
+ int socket_errno = 0;
+ ISC_SOCKLEN_T optlen;
+
+ UNUSED(evmask);
+
+ lalen = sizeof la;
+ ralen = sizeof ra;
+ conn_uap = conn->uap;
+ conn_func = conn->func;
+ id.opaque = conn;
+#ifdef SO_ERROR
+ optlen = sizeof socket_errno;
+ if (fd < 0 &&
+ getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno,
+ &optlen) < 0)
+ socket_errno = errno;
+ else
+ errno = socket_errno;
+#endif
+ if (evCancelConn(opaqueCtx, id) < 0 ||
+ socket_errno ||
+#ifdef NETREAD_BROKEN
+ 0 ||
+#else
+ read(fd, buf, 0) < 0 ||
+#endif
+ GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 ||
+ GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) {
+ int save = errno;
+
+ (void) close(fd); /*%< XXX closing caller's fd */
+ errno = save;
+ fd = -1;
+ }
+ (*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ev_files.c b/usr/src/lib/libresolv2_joy/common/isc/ev_files.c
new file mode 100644
index 0000000000..b12baf1aaa
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ev_files.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_files.c - implement asynch file IO for the eventlib
+ * vix 11sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_files.c,v 1.8 2005/07/28 06:51:48 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static evFile *FindFD(const evContext_p *ctx, int fd, int eventmask);
+
+int
+evSelectFD(evContext opaqueCtx,
+ int fd,
+ int eventmask,
+ evFileFunc func,
+ void *uap,
+ evFileID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evFile *id;
+ int mode;
+
+ evPrintf(ctx, 1,
+ "evSelectFD(ctx %p, fd %d, mask 0x%x, func %p, uap %p)\n",
+ ctx, fd, eventmask, func, uap);
+ if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0)
+ EV_ERR(EINVAL);
+#ifndef USE_POLL
+ if (fd > ctx->highestFD)
+ EV_ERR(EINVAL);
+#endif
+ OK(mode = fcntl(fd, F_GETFL, NULL)); /*%< side effect: validate fd. */
+ /*
+ * The first time we touch a file descriptor, we need to check to see
+ * if the application already had it in O_NONBLOCK mode and if so, all
+ * of our deselect()'s have to leave it in O_NONBLOCK. If not, then
+ * all but our last deselect() has to leave it in O_NONBLOCK.
+ */
+#ifdef USE_POLL
+ /* Make sure both ctx->pollfds[] and ctx->fdTable[] are large enough */
+ if (fd >= ctx->maxnfds && evPollfdRealloc(ctx, 1, fd) != 0)
+ EV_ERR(ENOMEM);
+#endif /* USE_POLL */
+ id = FindFD(ctx, fd, EV_MASK_ALL);
+ if (id == NULL) {
+ if (mode & PORT_NONBLOCK)
+ FD_SET(fd, &ctx->nonblockBefore);
+ else {
+#ifdef USE_FIONBIO_IOCTL
+ int on = 1;
+ OK(ioctl(fd, FIONBIO, (char *)&on));
+#else
+ OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
+#endif
+ FD_CLR(fd, &ctx->nonblockBefore);
+ }
+ }
+
+ /*
+ * If this descriptor is already in use, search for it again to see
+ * if any of the eventmask bits we want to set are already captured.
+ * We cannot usefully capture the same fd event more than once in the
+ * same context.
+ */
+ if (id != NULL && FindFD(ctx, fd, eventmask) != NULL)
+ EV_ERR(ETOOMANYREFS);
+
+ /* Allocate and fill. */
+ OKNEW(id);
+ id->func = func;
+ id->uap = uap;
+ id->fd = fd;
+ id->eventmask = eventmask;
+
+ /*
+ * Insert at head. Order could be important for performance if we
+ * believe that evGetNext()'s accesses to the fd_sets will be more
+ * serial and therefore more cache-lucky if the list is ordered by
+ * ``fd.'' We do not believe these things, so we don't do it.
+ *
+ * The interesting sequence is where GetNext() has cached a select()
+ * result and the caller decides to evSelectFD() on some descriptor.
+ * Since GetNext() starts at the head, it can miss new entries we add
+ * at the head. This is not a serious problem since the event being
+ * evSelectFD()'d for has to occur before evSelectFD() is called for
+ * the file event to be considered "missed" -- a real corner case.
+ * Maintaining a "tail" pointer for ctx->files would fix this, but I'm
+ * not sure it would be ``more correct.''
+ */
+ if (ctx->files != NULL)
+ ctx->files->prev = id;
+ id->prev = NULL;
+ id->next = ctx->files;
+ ctx->files = id;
+
+ /* Insert into fd table. */
+ if (ctx->fdTable[fd] != NULL)
+ ctx->fdTable[fd]->fdprev = id;
+ id->fdprev = NULL;
+ id->fdnext = ctx->fdTable[fd];
+ ctx->fdTable[fd] = id;
+
+ /* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */
+ if (eventmask & EV_READ)
+ FD_SET(fd, &ctx->rdNext);
+ if (eventmask & EV_WRITE)
+ FD_SET(fd, &ctx->wrNext);
+ if (eventmask & EV_EXCEPT)
+ FD_SET(fd, &ctx->exNext);
+
+ /* Update fdMax. */
+ if (fd > ctx->fdMax)
+ ctx->fdMax = fd;
+
+ /* Remember the ID if the caller provided us a place for it. */
+ if (opaqueID)
+ opaqueID->opaque = id;
+
+ return (0);
+}
+
+int
+evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evFile *del = opaqueID.opaque;
+ evFile *cur;
+ int mode, eventmask;
+
+ if (!del) {
+ evPrintf(ctx, 11, "evDeselectFD(NULL) ignored\n");
+ errno = EINVAL;
+ return (-1);
+ }
+
+ evPrintf(ctx, 1, "evDeselectFD(fd %d, mask 0x%x)\n",
+ del->fd, del->eventmask);
+
+ /* Get the mode. Unless the file has been closed, errors are bad. */
+ mode = fcntl(del->fd, F_GETFL, NULL);
+ if (mode == -1 && errno != EBADF)
+ EV_ERR(errno);
+
+ /* Remove from the list of files. */
+ if (del->prev != NULL)
+ del->prev->next = del->next;
+ else
+ ctx->files = del->next;
+ if (del->next != NULL)
+ del->next->prev = del->prev;
+
+ /* Remove from the fd table. */
+ if (del->fdprev != NULL)
+ del->fdprev->fdnext = del->fdnext;
+ else
+ ctx->fdTable[del->fd] = del->fdnext;
+ if (del->fdnext != NULL)
+ del->fdnext->fdprev = del->fdprev;
+
+ /*
+ * If the file descriptor does not appear in any other select() entry,
+ * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode
+ * earlier, then: restore the fd to blocking status.
+ */
+ if (!(cur = FindFD(ctx, del->fd, EV_MASK_ALL)) &&
+ !FD_ISSET(del->fd, &ctx->nonblockBefore) &&
+ mode != -1) {
+ /*
+ * Note that we won't return an error status to the caller if
+ * this fcntl() fails since (a) we've already done the work
+ * and (b) the caller didn't ask us anything about O_NONBLOCK.
+ */
+#ifdef USE_FIONBIO_IOCTL
+ int off = 0;
+ (void) ioctl(del->fd, FIONBIO, (char *)&off);
+#else
+ (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK);
+#endif
+ }
+
+ /*
+ * Now find all other uses of this descriptor and OR together an event
+ * mask so that we don't turn off {rd,wr,ex}Next bits that some other
+ * file event is using. As an optimization, stop if the event mask
+ * fills.
+ */
+ eventmask = 0;
+ for ((void)NULL;
+ cur != NULL && eventmask != EV_MASK_ALL;
+ cur = cur->next)
+ if (cur->fd == del->fd)
+ eventmask |= cur->eventmask;
+
+ /* OK, now we know which bits we can clear out. */
+ if (!(eventmask & EV_READ)) {
+ FD_CLR(del->fd, &ctx->rdNext);
+ if (FD_ISSET(del->fd, &ctx->rdLast)) {
+ FD_CLR(del->fd, &ctx->rdLast);
+ ctx->fdCount--;
+ }
+ }
+ if (!(eventmask & EV_WRITE)) {
+ FD_CLR(del->fd, &ctx->wrNext);
+ if (FD_ISSET(del->fd, &ctx->wrLast)) {
+ FD_CLR(del->fd, &ctx->wrLast);
+ ctx->fdCount--;
+ }
+ }
+ if (!(eventmask & EV_EXCEPT)) {
+ FD_CLR(del->fd, &ctx->exNext);
+ if (FD_ISSET(del->fd, &ctx->exLast)) {
+ FD_CLR(del->fd, &ctx->exLast);
+ ctx->fdCount--;
+ }
+ }
+
+ /* If this was the maxFD, find the new one. */
+ if (del->fd == ctx->fdMax) {
+ ctx->fdMax = -1;
+ for (cur = ctx->files; cur; cur = cur->next)
+ if (cur->fd > ctx->fdMax)
+ ctx->fdMax = cur->fd;
+ }
+
+ /* If this was the fdNext, cycle that to the next entry. */
+ if (del == ctx->fdNext)
+ ctx->fdNext = del->next;
+
+ /* Couldn't free it before now since we were using fields out of it. */
+ FREE(del);
+
+ return (0);
+}
+
+static evFile *
+FindFD(const evContext_p *ctx, int fd, int eventmask) {
+ evFile *id;
+
+ for (id = ctx->fdTable[fd]; id != NULL; id = id->fdnext)
+ if (id->fd == fd && (id->eventmask & eventmask) != 0)
+ break;
+ return (id);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ev_streams.c b/usr/src/lib/libresolv2_joy/common/isc/ev_streams.c
new file mode 100644
index 0000000000..5dad36d04a
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ev_streams.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_streams.c - implement asynch stream file IO for the eventlib
+ * vix 04mar96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static int copyvec(evStream *str, const struct iovec *iov, int iocnt);
+static void consume(evStream *str, size_t bytes);
+static void done(evContext opaqueCtx, evStream *str);
+static void writable(evContext opaqueCtx, void *uap, int fd, int evmask);
+static void readable(evContext opaqueCtx, void *uap, int fd, int evmask);
+
+struct iovec
+evConsIovec(void *buf, size_t cnt) {
+ struct iovec ret;
+
+ memset(&ret, 0xf5, sizeof ret);
+ ret.iov_base = buf;
+ ret.iov_len = cnt;
+ return (ret);
+}
+
+int
+evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id != NULL)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+ evStreamFunc func, void *uap, evStreamID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *new;
+ int save;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->fd = fd;
+ new->flags = 0;
+ if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
+ goto free;
+ if (copyvec(new, iov, iocnt) < 0)
+ goto free;
+ new->prevDone = NULL;
+ new->nextDone = NULL;
+ if (ctx->streams != NULL)
+ ctx->streams->prev = new;
+ new->prev = NULL;
+ new->next = ctx->streams;
+ ctx->streams = new;
+ if (id)
+ id->opaque = new;
+ return (0);
+ free:
+ save = errno;
+ FREE(new);
+ errno = save;
+ return (-1);
+}
+
+int
+evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->timer = timer;
+ str->flags |= EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
+ evStream *str = id.opaque;
+
+ UNUSED(opaqueCtx);
+
+ str->flags &= ~EV_STR_TIMEROK;
+ return (0);
+}
+
+int
+evCancelRW(evContext opaqueCtx, evStreamID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evStream *old = id.opaque;
+
+ /*
+ * The streams list is doubly threaded. First, there's ctx->streams
+ * that's used by evDestroy() to find and cancel all streams. Second,
+ * there's ctx->strDone (head) and ctx->strLast (tail) which thread
+ * through the potentially smaller number of "IO completed" streams,
+ * used in evGetNext() to avoid scanning the entire list.
+ */
+
+ /* Unlink from ctx->streams. */
+ if (old->prev != NULL)
+ old->prev->next = old->next;
+ else
+ ctx->streams = old->next;
+ if (old->next != NULL)
+ old->next->prev = old->prev;
+
+ /*
+ * If 'old' is on the ctx->strDone list, remove it. Update
+ * ctx->strLast if necessary.
+ */
+ if (old->prevDone == NULL && old->nextDone == NULL) {
+ /*
+ * Either 'old' is the only item on the done list, or it's
+ * not on the done list. If the former, then we unlink it
+ * from the list. If the latter, we leave the list alone.
+ */
+ if (ctx->strDone == old) {
+ ctx->strDone = NULL;
+ ctx->strLast = NULL;
+ }
+ } else {
+ if (old->prevDone != NULL)
+ old->prevDone->nextDone = old->nextDone;
+ else
+ ctx->strDone = old->nextDone;
+ if (old->nextDone != NULL)
+ old->nextDone->prevDone = old->prevDone;
+ else
+ ctx->strLast = old->prevDone;
+ }
+
+ /* Deallocate the stream. */
+ if (old->file.opaque)
+ evDeselectFD(opaqueCtx, old->file);
+ memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
+ FREE(old);
+ return (0);
+}
+
+/* Copy a scatter/gather vector and initialize a stream handler's IO. */
+static int
+copyvec(evStream *str, const struct iovec *iov, int iocnt) {
+ int i;
+
+ str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
+ if (str->iovOrig == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ str->ioTotal = 0;
+ for (i = 0; i < iocnt; i++) {
+ str->iovOrig[i] = iov[i];
+ str->ioTotal += iov[i].iov_len;
+ }
+ str->iovOrigCount = iocnt;
+ str->iovCur = str->iovOrig;
+ str->iovCurCount = str->iovOrigCount;
+ str->ioDone = 0;
+ return (0);
+}
+
+/* Pull off or truncate lead iovec(s). */
+static void
+consume(evStream *str, size_t bytes) {
+ while (bytes > 0U) {
+ if (bytes < (size_t)str->iovCur->iov_len) {
+ str->iovCur->iov_len -= bytes;
+ str->iovCur->iov_base = (void *)
+ ((u_char *)str->iovCur->iov_base + bytes);
+ str->ioDone += bytes;
+ bytes = 0;
+ } else {
+ bytes -= str->iovCur->iov_len;
+ str->ioDone += str->iovCur->iov_len;
+ str->iovCur++;
+ str->iovCurCount--;
+ }
+ }
+}
+
+/* Add a stream to Done list and deselect the FD. */
+static void
+done(evContext opaqueCtx, evStream *str) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ if (ctx->strLast != NULL) {
+ str->prevDone = ctx->strLast;
+ ctx->strLast->nextDone = str;
+ ctx->strLast = str;
+ } else {
+ INSIST(ctx->strDone == NULL);
+ ctx->strDone = ctx->strLast = str;
+ }
+ evDeselectFD(opaqueCtx, str->file);
+ str->file.opaque = NULL;
+ /* evDrop() will call evCancelRW() on us. */
+}
+
+/* Dribble out some bytes on the stream. (Called by evDispatch().) */
+static void
+writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = writev(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes < 0 && errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ if (str->ioDone == -1 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+
+/* Scoop up some bytes from the stream. (Called by evDispatch().) */
+static void
+readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+ evStream *str = uap;
+ int bytes;
+
+ UNUSED(evmask);
+
+ bytes = readv(fd, str->iovCur, str->iovCurCount);
+ if (bytes > 0) {
+ if ((str->flags & EV_STR_TIMEROK) != 0)
+ evTouchIdleTimer(opaqueCtx, str->timer);
+ consume(str, bytes);
+ } else {
+ if (bytes == 0)
+ str->ioDone = 0;
+ else {
+ if (errno != EINTR) {
+ str->ioDone = -1;
+ str->ioErrno = errno;
+ }
+ }
+ }
+ if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
+ done(opaqueCtx, str);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ev_timers.c b/usr/src/lib/libresolv2_joy/common/isc/ev_timers.c
new file mode 100644
index 0000000000..12ac2cebca
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ev_timers.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_timers.c - implement timers for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+#define MILLION 1000000
+#define BILLION 1000000000
+
+/* Forward. */
+
+static int due_sooner(void *, void *);
+static void set_index(void *, int);
+static void free_timer(void *, void *);
+static void print_timer(void *, void *);
+static void idle_timeout(evContext, void *, struct timespec, struct timespec);
+
+/* Private type. */
+
+typedef struct {
+ evTimerFunc func;
+ void * uap;
+ struct timespec lastTouched;
+ struct timespec max_idle;
+ evTimer * timer;
+} idle_timer;
+
+/* Public. */
+
+struct timespec
+evConsTime(time_t sec, long nsec) {
+ struct timespec x;
+
+ x.tv_sec = sec;
+ x.tv_nsec = nsec;
+ return (x);
+}
+
+struct timespec
+evAddTime(struct timespec addend1, struct timespec addend2) {
+ struct timespec x;
+
+ x.tv_sec = addend1.tv_sec + addend2.tv_sec;
+ x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
+ if (x.tv_nsec >= BILLION) {
+ x.tv_sec++;
+ x.tv_nsec -= BILLION;
+ }
+ return (x);
+}
+
+struct timespec
+evSubTime(struct timespec minuend, struct timespec subtrahend) {
+ struct timespec x;
+
+ x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
+ if (minuend.tv_nsec >= subtrahend.tv_nsec)
+ x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
+ else {
+ x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
+ x.tv_sec--;
+ }
+ return (x);
+}
+
+int
+evCmpTime(struct timespec a, struct timespec b) {
+ long x = a.tv_sec - b.tv_sec;
+
+ if (x == 0L)
+ x = a.tv_nsec - b.tv_nsec;
+ return (x < 0L ? (-1) : x > 0L ? (1) : (0));
+}
+
+struct timespec
+evNowTime() {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ int m = CLOCK_REALTIME;
+
+#ifdef CLOCK_MONOTONIC
+ if (__evOptMonoTime)
+ m = CLOCK_MONOTONIC;
+#endif
+ if (clock_gettime(m, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+struct timespec
+evUTCTime() {
+ struct timeval now;
+#ifdef CLOCK_REALTIME
+ struct timespec tsnow;
+ if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
+ return (tsnow);
+#endif
+ if (gettimeofday(&now, NULL) < 0)
+ return (evConsTime(0, 0));
+ return (evTimeSpec(now));
+}
+
+struct timespec
+evLastEventTime(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->lastEventTime);
+}
+
+struct timespec
+evTimeSpec(struct timeval tv) {
+ struct timespec ts;
+
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return (ts);
+}
+
+struct timeval
+evTimeVal(struct timespec ts) {
+ struct timeval tv;
+
+ tv.tv_sec = ts.tv_sec;
+ tv.tv_usec = ts.tv_nsec / 1000;
+ return (tv);
+}
+
+int
+evSetTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *id;
+
+ evPrintf(ctx, 1,
+"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
+ ctx, func, uap,
+ (long)due.tv_sec, due.tv_nsec,
+ (long)inter.tv_sec, inter.tv_nsec);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ /* due={0,0} is a magic cookie meaning "now." */
+ if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
+ due = evNowTime();
+
+ /* Allocate and fill. */
+ OKNEW(id);
+ id->func = func;
+ id->uap = uap;
+ id->due = due;
+ id->inter = inter;
+
+ if (heap_insert(ctx->timers, id) < 0)
+ return (-1);
+
+ /* Remember the ID if the caller provided us a place for it. */
+ if (opaqueID)
+ opaqueID->opaque = id;
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evSetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evClearTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *del = id.opaque;
+
+ if (ctx->cur != NULL &&
+ ctx->cur->type == Timer &&
+ ctx->cur->u.timer.this == del) {
+ evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
+ /*
+ * Setting the interval to zero ensures that evDrop() will
+ * clean up the timer.
+ */
+ del->inter = evConsTime(0, 0);
+ return (0);
+ }
+
+ if (heap_element(ctx->timers, del->index) != del)
+ EV_ERR(ENOENT);
+
+ if (heap_delete(ctx->timers, del->index) < 0)
+ return (-1);
+ FREE(del);
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evClearTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (0);
+}
+
+int
+evConfigTimer(evContext opaqueCtx,
+ evTimerID id,
+ const char *param,
+ int value
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ int result=0;
+
+ UNUSED(value);
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+ if (strcmp(param, "rate") == 0)
+ timer->mode |= EV_TMR_RATE;
+ else if (strcmp(param, "interval") == 0)
+ timer->mode &= ~EV_TMR_RATE;
+ else
+ EV_ERR(EINVAL);
+
+ return (result);
+}
+
+int
+evResetTimer(evContext opaqueCtx,
+ evTimerID id,
+ evTimerFunc func,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = id.opaque;
+ struct timespec old_due;
+ int result=0;
+
+ if (heap_element(ctx->timers, timer->index) != timer)
+ EV_ERR(ENOENT);
+
+#ifdef __hpux
+ /*
+ * tv_sec and tv_nsec are unsigned.
+ */
+ if (due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#else
+ if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+
+ if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
+ EV_ERR(EINVAL);
+#endif
+
+ old_due = timer->due;
+
+ timer->func = func;
+ timer->uap = uap;
+ timer->due = due;
+ timer->inter = inter;
+
+ switch (evCmpTime(due, old_due)) {
+ case -1:
+ result = heap_increased(ctx->timers, timer->index);
+ break;
+ case 0:
+ result = 0;
+ break;
+ case 1:
+ result = heap_decreased(ctx->timers, timer->index);
+ break;
+ }
+
+ if (ctx->debug > 7) {
+ evPrintf(ctx, 7, "timers after evResetTimer:\n");
+ (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+ }
+
+ return (result);
+}
+
+int
+evSetIdleTimer(evContext opaqueCtx,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle,
+ evTimerID *opaqueID
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *tt;
+
+ /* Allocate and fill. */
+ OKNEW(tt);
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ if (evSetTimer(opaqueCtx, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle, opaqueID) < 0) {
+ FREE(tt);
+ return (-1);
+ }
+
+ tt->timer = opaqueID->opaque;
+
+ return (0);
+}
+
+int
+evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evTimer *del = id.opaque;
+ idle_timer *tt = del->uap;
+
+ FREE(tt);
+ return (evClearTimer(opaqueCtx, id));
+}
+
+int
+evResetIdleTimer(evContext opaqueCtx,
+ evTimerID opaqueID,
+ evTimerFunc func,
+ void *uap,
+ struct timespec max_idle
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *timer = opaqueID.opaque;
+ idle_timer *tt = timer->uap;
+
+ tt->func = func;
+ tt->uap = uap;
+ tt->lastTouched = ctx->lastEventTime;
+ tt->max_idle = max_idle;
+
+ return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
+ evAddTime(ctx->lastEventTime, max_idle),
+ max_idle));
+}
+
+int
+evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evTimer *t = id.opaque;
+ idle_timer *tt = t->uap;
+
+ tt->lastTouched = ctx->lastEventTime;
+
+ return (0);
+}
+
+/* Public to the rest of eventlib. */
+
+heap_context
+evCreateTimers(const evContext_p *ctx) {
+
+ UNUSED(ctx);
+
+ return (heap_new(due_sooner, set_index, 2048));
+}
+
+void
+evDestroyTimers(const evContext_p *ctx) {
+ (void) heap_for_each(ctx->timers, free_timer, NULL);
+ (void) heap_free(ctx->timers);
+}
+
+/* Private. */
+
+static int
+due_sooner(void *a, void *b) {
+ evTimer *a_timer, *b_timer;
+
+ a_timer = a;
+ b_timer = b;
+ return (evCmpTime(a_timer->due, b_timer->due) < 0);
+}
+
+static void
+set_index(void *what, int index) {
+ evTimer *timer;
+
+ timer = what;
+ timer->index = index;
+}
+
+static void
+free_timer(void *what, void *uap) {
+ evTimer *t = what;
+
+ UNUSED(uap);
+
+ FREE(t);
+}
+
+static void
+print_timer(void *what, void *uap) {
+ evTimer *cur = what;
+ evContext_p *ctx = uap;
+
+ cur = what;
+ evPrintf(ctx, 7,
+ " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
+ cur->func, cur->uap,
+ (long)cur->due.tv_sec, cur->due.tv_nsec,
+ (long)cur->inter.tv_sec, cur->inter.tv_nsec);
+}
+
+static void
+idle_timeout(evContext opaqueCtx,
+ void *uap,
+ struct timespec due,
+ struct timespec inter
+) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ idle_timer *this = uap;
+ struct timespec idle;
+
+ UNUSED(due);
+ UNUSED(inter);
+
+ idle = evSubTime(ctx->lastEventTime, this->lastTouched);
+ if (evCmpTime(idle, this->max_idle) >= 0) {
+ (this->func)(opaqueCtx, this->uap, this->timer->due,
+ this->max_idle);
+ /*
+ * Setting the interval to zero will cause the timer to
+ * be cleaned up in evDrop().
+ */
+ this->timer->inter = evConsTime(0, 0);
+ FREE(this);
+ } else {
+ /* evDrop() will reschedule the timer. */
+ this->timer->inter = evSubTime(this->max_idle, idle);
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/ev_waits.c b/usr/src/lib/libresolv2_joy/common/isc/ev_waits.c
new file mode 100644
index 0000000000..99da1526c7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/ev_waits.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ev_waits.c - implement deferred function calls for the eventlib
+ * vix 05dec95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_waits.c,v 1.4 2005/04/27 04:56:36 sra Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void print_waits(evContext_p *ctx);
+static evWaitList * evNewWaitList(evContext_p *);
+static void evFreeWaitList(evContext_p *, evWaitList *);
+static evWaitList * evGetWaitList(evContext_p *, const void *, int);
+
+
+/* Public. */
+
+/*%
+ * Enter a new wait function on the queue.
+ */
+int
+evWaitFor(evContext opaqueCtx, const void *tag,
+ evWaitFunc func, void *uap, evWaitID *id)
+{
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *new;
+ evWaitList *wl = evGetWaitList(ctx, tag, 1);
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->tag = tag;
+ new->next = NULL;
+ if (wl->last != NULL)
+ wl->last->next = new;
+ else
+ wl->first = new;
+ wl->last = new;
+ if (id != NULL)
+ id->opaque = new;
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+ return (0);
+}
+
+/*%
+ * Mark runnable all waiting functions having a certain tag.
+ */
+int
+evDo(evContext opaqueCtx, const void *tag) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWaitList *wl = evGetWaitList(ctx, tag, 0);
+ evWait *first;
+
+ if (!wl) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ first = wl->first;
+ INSIST(first != NULL);
+
+ if (ctx->waitDone.last != NULL)
+ ctx->waitDone.last->next = first;
+ else
+ ctx->waitDone.first = first;
+ ctx->waitDone.last = wl->last;
+ evFreeWaitList(ctx, wl);
+
+ return (0);
+}
+
+/*%
+ * Remove a waiting (or ready to run) function from the queue.
+ */
+int
+evUnwait(evContext opaqueCtx, evWaitID id) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *this, *prev;
+ evWaitList *wl;
+ int found = 0;
+
+ this = id.opaque;
+ INSIST(this != NULL);
+ wl = evGetWaitList(ctx, this->tag, 0);
+ if (wl != NULL) {
+ for (prev = NULL, this = wl->first;
+ this != NULL;
+ prev = this, this = this->next)
+ if (this == (evWait *)id.opaque) {
+ found = 1;
+ if (prev != NULL)
+ prev->next = this->next;
+ else
+ wl->first = this->next;
+ if (wl->last == this)
+ wl->last = prev;
+ if (wl->first == NULL)
+ evFreeWaitList(ctx, wl);
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Maybe it's done */
+ for (prev = NULL, this = ctx->waitDone.first;
+ this != NULL;
+ prev = this, this = this->next)
+ if (this == (evWait *)id.opaque) {
+ found = 1;
+ if (prev != NULL)
+ prev->next = this->next;
+ else
+ ctx->waitDone.first = this->next;
+ if (ctx->waitDone.last == this)
+ ctx->waitDone.last = prev;
+ break;
+ }
+ }
+
+ if (!found) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ FREE(this);
+
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+
+ return (0);
+}
+
+int
+evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evWait *new;
+
+ OKNEW(new);
+ new->func = func;
+ new->uap = uap;
+ new->tag = NULL;
+ new->next = NULL;
+ if (ctx->waitDone.last != NULL)
+ ctx->waitDone.last->next = new;
+ else
+ ctx->waitDone.first = new;
+ ctx->waitDone.last = new;
+ if (ctx->debug >= 9)
+ print_waits(ctx);
+ return (0);
+}
+
+/* Private. */
+
+static void
+print_waits(evContext_p *ctx) {
+ evWaitList *wl;
+ evWait *this;
+
+ evPrintf(ctx, 9, "wait waiting:\n");
+ for (wl = ctx->waitLists; wl != NULL; wl = wl->next) {
+ INSIST(wl->first != NULL);
+ evPrintf(ctx, 9, " tag %p:", wl->first->tag);
+ for (this = wl->first; this != NULL; this = this->next)
+ evPrintf(ctx, 9, " %p", this);
+ evPrintf(ctx, 9, "\n");
+ }
+ evPrintf(ctx, 9, "wait done:");
+ for (this = ctx->waitDone.first; this != NULL; this = this->next)
+ evPrintf(ctx, 9, " %p", this);
+ evPrintf(ctx, 9, "\n");
+}
+
+static evWaitList *
+evNewWaitList(evContext_p *ctx) {
+ evWaitList *new;
+
+ NEW(new);
+ if (new == NULL)
+ return (NULL);
+ new->first = new->last = NULL;
+ new->prev = NULL;
+ new->next = ctx->waitLists;
+ if (new->next != NULL)
+ new->next->prev = new;
+ ctx->waitLists = new;
+ return (new);
+}
+
+static void
+evFreeWaitList(evContext_p *ctx, evWaitList *this) {
+
+ INSIST(this != NULL);
+
+ if (this->prev != NULL)
+ this->prev->next = this->next;
+ else
+ ctx->waitLists = this->next;
+ if (this->next != NULL)
+ this->next->prev = this->prev;
+ FREE(this);
+}
+
+static evWaitList *
+evGetWaitList(evContext_p *ctx, const void *tag, int should_create) {
+ evWaitList *this;
+
+ for (this = ctx->waitLists; this != NULL; this = this->next) {
+ if (this->first != NULL && this->first->tag == tag)
+ break;
+ }
+ if (this == NULL && should_create)
+ this = evNewWaitList(ctx);
+ return (this);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/eventlib.c b/usr/src/lib/libresolv2_joy/common/isc/eventlib.c
new file mode 100644
index 0000000000..be4a7848b9
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/eventlib.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* eventlib.c - implement glue for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef SOLARIS2
+#include <limits.h>
+#endif /* SOLARIS2 */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+int __evOptMonoTime;
+
+#ifdef USE_POLL
+#define pselect Pselect
+#endif /* USE_POLL */
+
+/* Forward. */
+
+#if defined(NEED_PSELECT) || defined(USE_POLL)
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
+#endif
+
+int __evOptMonoTime;
+
+/* Public. */
+
+int
+evCreate(evContext *opaqueCtx) {
+ evContext_p *ctx;
+
+ /* Make sure the memory heap is initialized. */
+ if (meminit(0, 0) < 0 && errno != EEXIST)
+ return (-1);
+
+ OKNEW(ctx);
+
+ /* Global. */
+ ctx->cur = NULL;
+
+ /* Debugging. */
+ ctx->debug = 0;
+ ctx->output = NULL;
+
+ /* Connections. */
+ ctx->conns = NULL;
+ INIT_LIST(ctx->accepts);
+
+ /* Files. */
+ ctx->files = NULL;
+#ifdef USE_POLL
+ ctx->pollfds = NULL;
+ ctx->maxnfds = 0;
+ ctx->firstfd = 0;
+ emulMaskInit(ctx, rdLast, EV_READ, 1);
+ emulMaskInit(ctx, rdNext, EV_READ, 0);
+ emulMaskInit(ctx, wrLast, EV_WRITE, 1);
+ emulMaskInit(ctx, wrNext, EV_WRITE, 0);
+ emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
+ emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
+ emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
+#endif /* USE_POLL */
+ FD_ZERO(&ctx->rdNext);
+ FD_ZERO(&ctx->wrNext);
+ FD_ZERO(&ctx->exNext);
+ FD_ZERO(&ctx->nonblockBefore);
+ ctx->fdMax = -1;
+ ctx->fdNext = NULL;
+ ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */
+#ifndef USE_POLL
+ ctx->highestFD = FD_SETSIZE - 1;
+ memset(ctx->fdTable, 0, sizeof ctx->fdTable);
+#else
+ ctx->highestFD = INT_MAX / sizeof(struct pollfd);
+ ctx->fdTable = NULL;
+#endif /* USE_POLL */
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastFdCount = 0;
+#endif
+
+ /* Streams. */
+ ctx->streams = NULL;
+ ctx->strDone = NULL;
+ ctx->strLast = NULL;
+
+ /* Timers. */
+ ctx->lastEventTime = evNowTime();
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+ ctx->timers = evCreateTimers(ctx);
+ if (ctx->timers == NULL)
+ return (-1);
+
+ /* Waits. */
+ ctx->waitLists = NULL;
+ ctx->waitDone.first = ctx->waitDone.last = NULL;
+ ctx->waitDone.prev = ctx->waitDone.next = NULL;
+
+ opaqueCtx->opaque = ctx;
+ return (0);
+}
+
+void
+evSetDebug(evContext opaqueCtx, int level, FILE *output) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ ctx->debug = level;
+ ctx->output = output;
+}
+
+int
+evDestroy(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ int revs = 424242; /*%< Doug Adams. */
+ evWaitList *this_wl, *next_wl;
+ evWait *this_wait, *next_wait;
+
+ /* Connections. */
+ while (revs-- > 0 && ctx->conns != NULL) {
+ evConnID id;
+
+ id.opaque = ctx->conns;
+ (void) evCancelConn(opaqueCtx, id);
+ }
+ INSIST(revs >= 0);
+
+ /* Streams. */
+ while (revs-- > 0 && ctx->streams != NULL) {
+ evStreamID id;
+
+ id.opaque = ctx->streams;
+ (void) evCancelRW(opaqueCtx, id);
+ }
+
+ /* Files. */
+ while (revs-- > 0 && ctx->files != NULL) {
+ evFileID id;
+
+ id.opaque = ctx->files;
+ (void) evDeselectFD(opaqueCtx, id);
+ }
+ INSIST(revs >= 0);
+
+ /* Timers. */
+ evDestroyTimers(ctx);
+
+ /* Waits. */
+ for (this_wl = ctx->waitLists;
+ revs-- > 0 && this_wl != NULL;
+ this_wl = next_wl) {
+ next_wl = this_wl->next;
+ for (this_wait = this_wl->first;
+ revs-- > 0 && this_wait != NULL;
+ this_wait = next_wait) {
+ next_wait = this_wait->next;
+ FREE(this_wait);
+ }
+ FREE(this_wl);
+ }
+ for (this_wait = ctx->waitDone.first;
+ revs-- > 0 && this_wait != NULL;
+ this_wait = next_wait) {
+ next_wait = this_wait->next;
+ FREE(this_wait);
+ }
+
+ FREE(ctx);
+ return (0);
+}
+
+int
+evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ struct timespec nextTime;
+ evTimer *nextTimer;
+ evEvent_p *new;
+ int x, pselect_errno, timerPast;
+#ifdef EVENTLIB_TIME_CHECKS
+ struct timespec interval;
+#endif
+
+ /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
+ x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
+ if (x != 1)
+ EV_ERR(EINVAL);
+
+ /* Get the time of day. We'll do this again after select() blocks. */
+ ctx->lastEventTime = evNowTime();
+
+ again:
+ /* Finished accept()'s do not require a select(). */
+ if (!EMPTY(ctx->accepts)) {
+ OKNEW(new);
+ new->type = Accept;
+ new->u.accept.this = HEAD(ctx->accepts);
+ UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Stream IO does not require a select(). */
+ if (ctx->strDone != NULL) {
+ OKNEW(new);
+ new->type = Stream;
+ new->u.stream.this = ctx->strDone;
+ ctx->strDone = ctx->strDone->nextDone;
+ if (ctx->strDone == NULL)
+ ctx->strLast = NULL;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Waits do not require a select(). */
+ if (ctx->waitDone.first != NULL) {
+ OKNEW(new);
+ new->type = Wait;
+ new->u.wait.this = ctx->waitDone.first;
+ ctx->waitDone.first = ctx->waitDone.first->next;
+ if (ctx->waitDone.first == NULL)
+ ctx->waitDone.last = NULL;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* Get the status and content of the next timer. */
+ if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
+ nextTime = nextTimer->due;
+ timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+ } else
+ timerPast = 0; /*%< Make gcc happy. */
+ evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
+ if (ctx->fdCount == 0) {
+ static const struct timespec NoTime = {0, 0L};
+ enum { JustPoll, Block, Timer } m;
+ struct timespec t, *tp;
+
+ /* Are there any events at all? */
+ if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
+ EV_ERR(ENOENT);
+
+ /* Figure out what select()'s timeout parameter should be. */
+ if ((options & EV_POLL) != 0) {
+ m = JustPoll;
+ t = NoTime;
+ tp = &t;
+ } else if (nextTimer == NULL) {
+ m = Block;
+ /* ``t'' unused. */
+ tp = NULL;
+ } else if (timerPast) {
+ m = JustPoll;
+ t = NoTime;
+ tp = &t;
+ } else {
+ m = Timer;
+ /* ``t'' filled in later. */
+ tp = &t;
+ }
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0) {
+ interval = evSubTime(ctx->lastEventTime,
+ ctx->lastSelectTime);
+ if (interval.tv_sec > 0 || interval.tv_nsec > 0)
+ evPrintf(ctx, 1,
+ "time between pselect() %u.%09u count %d\n",
+ interval.tv_sec, interval.tv_nsec,
+ ctx->lastFdCount);
+ }
+#endif
+ do {
+#ifndef USE_POLL
+ /* XXX need to copy only the bits we are using. */
+ ctx->rdLast = ctx->rdNext;
+ ctx->wrLast = ctx->wrNext;
+ ctx->exLast = ctx->exNext;
+#else
+ /*
+ * The pollfd structure uses separate fields for
+ * the input and output events (corresponding to
+ * the ??Next and ??Last fd sets), so there's no
+ * need to copy one to the other.
+ */
+#endif /* USE_POLL */
+ if (m == Timer) {
+ INSIST(tp == &t);
+ t = evSubTime(nextTime, ctx->lastEventTime);
+ }
+
+ /* XXX should predict system's earliness and adjust. */
+ x = pselect(ctx->fdMax+1,
+ &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
+ tp, NULL);
+ pselect_errno = errno;
+
+#ifndef USE_POLL
+ evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
+ x, (x == -1) ? strerror(errno) : "none");
+#else
+ evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
+ x, (x == -1) ? strerror(errno) : "none");
+#endif /* USE_POLL */
+ /* Anything but a poll can change the time. */
+ if (m != JustPoll)
+ ctx->lastEventTime = evNowTime();
+
+ /* Select() likes to finish about 10ms early. */
+ } while (x == 0 && m == Timer &&
+ evCmpTime(ctx->lastEventTime, nextTime) < 0);
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+ if (x < 0) {
+ if (pselect_errno == EINTR) {
+ if ((options & EV_NULL) != 0)
+ goto again;
+ OKNEW(new);
+ new->type = Null;
+ /* No data. */
+ opaqueEv->opaque = new;
+ return (0);
+ }
+ if (pselect_errno == EBADF) {
+ for (x = 0; x <= ctx->fdMax; x++) {
+ struct stat sb;
+
+ if (FD_ISSET(x, &ctx->rdNext) == 0 &&
+ FD_ISSET(x, &ctx->wrNext) == 0 &&
+ FD_ISSET(x, &ctx->exNext) == 0)
+ continue;
+ if (fstat(x, &sb) == -1 &&
+ errno == EBADF)
+ evPrintf(ctx, 1, "EBADF: %d\n",
+ x);
+ }
+ abort();
+ }
+ EV_ERR(pselect_errno);
+ }
+ if (x == 0 && (nextTimer == NULL || !timerPast) &&
+ (options & EV_POLL))
+ EV_ERR(EWOULDBLOCK);
+ ctx->fdCount = x;
+#ifdef EVENTLIB_TIME_CHECKS
+ ctx->lastFdCount = x;
+#endif
+ }
+ INSIST(nextTimer || ctx->fdCount);
+
+ /* Timers go first since we'd like them to be accurate. */
+ if (nextTimer && !timerPast) {
+ /* Has anything happened since we blocked? */
+ timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+ }
+ if (nextTimer && timerPast) {
+ OKNEW(new);
+ new->type = Timer;
+ new->u.timer.this = nextTimer;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+
+ /* No timers, so there should be a ready file descriptor. */
+ x = 0;
+ while (ctx->fdCount > 0) {
+ evFile *fid;
+ int fd, eventmask;
+
+ if (ctx->fdNext == NULL) {
+ if (++x == 2) {
+ /*
+ * Hitting the end twice means that the last
+ * select() found some FD's which have since
+ * been deselected.
+ *
+ * On some systems, the count returned by
+ * selects is the total number of bits in
+ * all masks that are set, and on others it's
+ * the number of fd's that have some bit set,
+ * and on others, it's just broken. We
+ * always assume that it's the number of
+ * bits set in all masks, because that's what
+ * the man page says it should do, and
+ * the worst that can happen is we do an
+ * extra select().
+ */
+ ctx->fdCount = 0;
+ break;
+ }
+ ctx->fdNext = ctx->files;
+ }
+ fid = ctx->fdNext;
+ ctx->fdNext = fid->next;
+
+ fd = fid->fd;
+ eventmask = 0;
+ if (FD_ISSET(fd, &ctx->rdLast))
+ eventmask |= EV_READ;
+ if (FD_ISSET(fd, &ctx->wrLast))
+ eventmask |= EV_WRITE;
+ if (FD_ISSET(fd, &ctx->exLast))
+ eventmask |= EV_EXCEPT;
+ eventmask &= fid->eventmask;
+ if (eventmask != 0) {
+ if ((eventmask & EV_READ) != 0) {
+ FD_CLR(fd, &ctx->rdLast);
+ ctx->fdCount--;
+ }
+ if ((eventmask & EV_WRITE) != 0) {
+ FD_CLR(fd, &ctx->wrLast);
+ ctx->fdCount--;
+ }
+ if ((eventmask & EV_EXCEPT) != 0) {
+ FD_CLR(fd, &ctx->exLast);
+ ctx->fdCount--;
+ }
+ OKNEW(new);
+ new->type = File;
+ new->u.file.this = fid;
+ new->u.file.eventmask = eventmask;
+ opaqueEv->opaque = new;
+ return (0);
+ }
+ }
+ if (ctx->fdCount < 0) {
+ /*
+ * select()'s count is off on a number of systems, and
+ * can result in fdCount < 0.
+ */
+ evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
+ ctx->fdCount = 0;
+ }
+
+ /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
+ goto again;
+}
+
+int
+evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evEvent_p *ev = opaqueEv.opaque;
+#ifdef EVENTLIB_TIME_CHECKS
+ void *func;
+ struct timespec start_time;
+ struct timespec interval;
+#endif
+
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0)
+ start_time = evNowTime();
+#endif
+ ctx->cur = ev;
+ switch (ev->type) {
+ case Accept: {
+ evAccept *this = ev->u.accept.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
+ this->conn->fd, this->fd,
+ this->conn->func, this->conn->uap);
+ errno = this->ioErrno;
+ (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
+ &this->la, this->lalen,
+ &this->ra, this->ralen);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->conn->func;
+#endif
+ break;
+ }
+ case File: {
+ evFile *this = ev->u.file.this;
+ int eventmask = ev->u.file.eventmask;
+
+ evPrintf(ctx, 5,
+ "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
+ this->fd, this->eventmask, this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Stream: {
+ evStream *this = ev->u.stream.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Stream: fd %d, func %p, uap %p\n",
+ this->fd, this->func, this->uap);
+ errno = this->ioErrno;
+ (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Timer: {
+ evTimer *this = ev->u.timer.this;
+
+ evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
+ this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->due, this->inter);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Wait: {
+ evWait *this = ev->u.wait.this;
+
+ evPrintf(ctx, 5,
+ "Dispatch.Wait: tag %p, func %p, uap %p\n",
+ this->tag, this->func, this->uap);
+ (this->func)(opaqueCtx, this->uap, this->tag);
+#ifdef EVENTLIB_TIME_CHECKS
+ func = this->func;
+#endif
+ break;
+ }
+ case Null: {
+ /* No work. */
+#ifdef EVENTLIB_TIME_CHECKS
+ func = NULL;
+#endif
+ break;
+ }
+ default: {
+ abort();
+ }
+ }
+#ifdef EVENTLIB_TIME_CHECKS
+ if (ctx->debug > 0) {
+ interval = evSubTime(evNowTime(), start_time);
+ /*
+ * Complain if it took longer than 50 milliseconds.
+ *
+ * We call getuid() to make an easy to find mark in a kernel
+ * trace.
+ */
+ if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
+ evPrintf(ctx, 1,
+ "dispatch interval %u.%09u uid %d type %d func %p\n",
+ interval.tv_sec, interval.tv_nsec,
+ getuid(), ev->type, func);
+ }
+#endif
+ ctx->cur = NULL;
+ evDrop(opaqueCtx, opaqueEv);
+ return (0);
+}
+
+void
+evDrop(evContext opaqueCtx, evEvent opaqueEv) {
+ evContext_p *ctx = opaqueCtx.opaque;
+ evEvent_p *ev = opaqueEv.opaque;
+
+ switch (ev->type) {
+ case Accept: {
+ FREE(ev->u.accept.this);
+ break;
+ }
+ case File: {
+ /* No work. */
+ break;
+ }
+ case Stream: {
+ evStreamID id;
+
+ id.opaque = ev->u.stream.this;
+ (void) evCancelRW(opaqueCtx, id);
+ break;
+ }
+ case Timer: {
+ evTimer *this = ev->u.timer.this;
+ evTimerID opaque;
+
+ /* Check to see whether the user func cleared the timer. */
+ if (heap_element(ctx->timers, this->index) != this) {
+ evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
+ break;
+ }
+ /*
+ * Timer is still there. Delete it if it has expired,
+ * otherwise set it according to its next interval.
+ */
+ if (this->inter.tv_sec == (time_t)0 &&
+ this->inter.tv_nsec == 0L) {
+ opaque.opaque = this;
+ (void) evClearTimer(opaqueCtx, opaque);
+ } else {
+ opaque.opaque = this;
+ (void) evResetTimer(opaqueCtx, opaque, this->func,
+ this->uap,
+ evAddTime((this->mode & EV_TMR_RATE) ?
+ this->due :
+ ctx->lastEventTime,
+ this->inter),
+ this->inter);
+ }
+ break;
+ }
+ case Wait: {
+ FREE(ev->u.wait.this);
+ break;
+ }
+ case Null: {
+ /* No work. */
+ break;
+ }
+ default: {
+ abort();
+ }
+ }
+ FREE(ev);
+}
+
+int
+evMainLoop(evContext opaqueCtx) {
+ evEvent event;
+ int x;
+
+ while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
+ if ((x = evDispatch(opaqueCtx, event)) < 0)
+ break;
+ return (x);
+}
+
+int
+evHighestFD(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->highestFD);
+}
+
+void
+evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (ctx->output != NULL && ctx->debug >= level) {
+ vfprintf(ctx->output, fmt, ap);
+ fflush(ctx->output);
+ }
+ va_end(ap);
+}
+
+int
+evSetOption(evContext *opaqueCtx, const char *option, int value) {
+ /* evContext_p *ctx = opaqueCtx->opaque; */
+
+ UNUSED(opaqueCtx);
+ UNUSED(value);
+#ifndef CLOCK_MONOTONIC
+ UNUSED(option);
+#endif
+
+#ifdef CLOCK_MONOTONIC
+ if (strcmp(option, "monotime") == 0) {
+ if (opaqueCtx != NULL)
+ errno = EINVAL;
+ if (value == 0 || value == 1) {
+ __evOptMonoTime = value;
+ return (0);
+ } else {
+ errno = EINVAL;
+ return (-1);
+ }
+ }
+#endif
+ errno = ENOENT;
+ return (-1);
+}
+
+int
+evGetOption(evContext *opaqueCtx, const char *option, int *value) {
+ /* evContext_p *ctx = opaqueCtx->opaque; */
+
+ UNUSED(opaqueCtx);
+#ifndef CLOCK_MONOTONIC
+ UNUSED(value);
+ UNUSED(option);
+#endif
+
+#ifdef CLOCK_MONOTONIC
+ if (strcmp(option, "monotime") == 0) {
+ if (opaqueCtx != NULL)
+ errno = EINVAL;
+ *value = __evOptMonoTime;
+ return (0);
+ }
+#endif
+ errno = ENOENT;
+ return (-1);
+}
+
+#if defined(NEED_PSELECT) || defined(USE_POLL)
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp,
+ const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp;
+ sigset_t sigs;
+ int n;
+#ifdef USE_POLL
+ int polltimeout = INFTIM;
+ evContext_p *ctx;
+ struct pollfd *fds;
+ nfds_t pnfds;
+
+ UNUSED(nfds);
+#endif /* USE_POLL */
+
+ if (tsp) {
+ tvp = &tv;
+ tv = evTimeVal(*tsp);
+#ifdef USE_POLL
+ polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
+#endif /* USE_POLL */
+ } else
+ tvp = NULL;
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, sigmask, &sigs);
+#ifndef USE_POLL
+ n = select(nfds, rfds, wfds, efds, tvp);
+#else
+ /*
+ * rfds, wfds, and efds should all be from the same evContext_p,
+ * so any of them will do. If they're all NULL, the caller is
+ * presumably calling us to block.
+ */
+ if (rfds != NULL)
+ ctx = ((__evEmulMask *)rfds)->ctx;
+ else if (wfds != NULL)
+ ctx = ((__evEmulMask *)wfds)->ctx;
+ else if (efds != NULL)
+ ctx = ((__evEmulMask *)efds)->ctx;
+ else
+ ctx = NULL;
+ if (ctx != NULL && ctx->fdMax != -1) {
+ fds = &(ctx->pollfds[ctx->firstfd]);
+ pnfds = ctx->fdMax - ctx->firstfd + 1;
+ } else {
+ fds = NULL;
+ pnfds = 0;
+ }
+ n = poll(fds, pnfds, polltimeout);
+ if (n > 0) {
+ int i, e;
+
+ INSIST(ctx != NULL);
+ for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
+ if (ctx->pollfds[i].fd < 0)
+ continue;
+ if (FD_ISSET(i, &ctx->rdLast))
+ e++;
+ if (FD_ISSET(i, &ctx->wrLast))
+ e++;
+ if (FD_ISSET(i, &ctx->exLast))
+ e++;
+ }
+ n = e;
+ }
+#endif /* USE_POLL */
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+ if (tsp)
+ *tsp = evTimeSpec(tv);
+ return (n);
+}
+#endif
+
+#ifdef USE_POLL
+int
+evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
+
+ int i, maxnfds;
+ void *pollfds, *fdTable;
+
+ if (fd < ctx->maxnfds)
+ return (0);
+
+ /* Don't allow ridiculously small values for pollfd_chunk_size */
+ if (pollfd_chunk_size < 20)
+ pollfd_chunk_size = 20;
+
+ maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
+
+ pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
+ if (pollfds != NULL)
+ ctx->pollfds = pollfds;
+ fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
+ if (fdTable != NULL)
+ ctx->fdTable = fdTable;
+
+ if (pollfds == NULL || fdTable == NULL) {
+ evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
+ (long)maxnfds*sizeof(struct pollfd));
+ return (-1);
+ }
+
+ for (i = ctx->maxnfds; i < maxnfds; i++) {
+ ctx->pollfds[i].fd = -1;
+ ctx->pollfds[i].events = 0;
+ ctx->fdTable[i] = 0;
+ }
+
+ ctx->maxnfds = maxnfds;
+
+ return (0);
+}
+
+/* Find the appropriate 'events' or 'revents' field in the pollfds array */
+short *
+__fd_eventfield(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = (evContext_p *)maskp->ctx;
+
+ if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
+ return (&(ctx->pollfds[fd].events));
+ else
+ return (&(ctx->pollfds[fd].revents));
+}
+
+/* Translate to poll(2) event */
+short
+__poll_event(__evEmulMask *maskp) {
+
+ switch ((maskp)->type) {
+ case EV_READ:
+ return (POLLRDNORM);
+ case EV_WRITE:
+ return (POLLWRNORM);
+ case EV_EXCEPT:
+ return (POLLRDBAND | POLLPRI | POLLWRBAND);
+ case EV_WASNONBLOCKING:
+ return (POLLHUP);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * Clear the events corresponding to the specified mask. If this leaves
+ * the events mask empty (apart from the POLLHUP bit), set the fd field
+ * to -1 so that poll(2) will ignore this fd.
+ */
+void
+__fd_clr(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = maskp->ctx;
+
+ *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
+ if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
+ ctx->pollfds[fd].fd = -1;
+ if (fd == ctx->fdMax)
+ while (ctx->fdMax > ctx->firstfd &&
+ ctx->pollfds[ctx->fdMax].fd < 0)
+ ctx->fdMax--;
+ if (fd == ctx->firstfd)
+ while (ctx->firstfd <= ctx->fdMax &&
+ ctx->pollfds[ctx->firstfd].fd < 0)
+ ctx->firstfd++;
+ /*
+ * Do we have a empty set of descriptors?
+ */
+ if (ctx->firstfd > ctx->fdMax) {
+ ctx->fdMax = -1;
+ ctx->firstfd = 0;
+ }
+ }
+}
+
+/*
+ * Set the events bit(s) corresponding to the specified mask. If the events
+ * field has any other bits than POLLHUP set, also set the fd field so that
+ * poll(2) will watch this fd.
+ */
+void
+__fd_set(int fd, __evEmulMask *maskp) {
+
+ evContext_p *ctx = maskp->ctx;
+
+ *__fd_eventfield(fd, maskp) |= __poll_event(maskp);
+ if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
+ ctx->pollfds[fd].fd = fd;
+ if (fd < ctx->firstfd || ctx->fdMax == -1)
+ ctx->firstfd = fd;
+ if (fd > ctx->fdMax)
+ ctx->fdMax = fd;
+ }
+}
+#endif /* USE_POLL */
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/eventlib_p.h b/usr/src/lib/libresolv2_joy/common/isc/eventlib_p.h
new file mode 100644
index 0000000000..0a3614ab23
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/eventlib_p.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief private interfaces for eventlib
+ * \author vix 09sep95 [initial]
+ *
+ * $Id: eventlib_p.h,v 1.9 2006/03/09 23:57:56 marka Exp $
+ */
+
+#ifndef _EVENTLIB_P_H
+#define _EVENTLIB_P_H
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#define EVENTLIB_DEBUG 1
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/heap.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#define EV_MASK_ALL (EV_READ | EV_WRITE | EV_EXCEPT)
+#define EV_ERR(e) return (errno = (e), -1)
+#define OK(x) if ((x) < 0) EV_ERR(errno); else (void)NULL
+#define OKFREE(x, y) if ((x) < 0) { FREE((y)); EV_ERR(errno); } \
+ else (void)NULL
+
+#define NEW(p) if (((p) = memget(sizeof *(p))) != NULL) \
+ FILL(p); \
+ else \
+ (void)NULL;
+#define OKNEW(p) if (!((p) = memget(sizeof *(p)))) { \
+ errno = ENOMEM; \
+ return (-1); \
+ } else \
+ FILL(p)
+#define FREE(p) memput((p), sizeof *(p))
+
+#if EVENTLIB_DEBUG
+#define FILL(p) memset((p), 0xF5, sizeof *(p))
+#else
+#define FILL(p)
+#endif
+
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+
+typedef struct evConn {
+ evConnFunc func;
+ void * uap;
+ int fd;
+ int flags;
+#define EV_CONN_LISTEN 0x0001 /*%< Connection is a listener. */
+#define EV_CONN_SELECTED 0x0002 /*%< evSelectFD(conn->file). */
+#define EV_CONN_BLOCK 0x0004 /*%< Listener fd was blocking. */
+ evFileID file;
+ struct evConn * prev;
+ struct evConn * next;
+} evConn;
+
+typedef struct evAccept {
+ int fd;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } la;
+ ISC_SOCKLEN_T lalen;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+ struct sockaddr_un un;
+#endif
+ } ra;
+ ISC_SOCKLEN_T ralen;
+ int ioErrno;
+ evConn * conn;
+ LINK(struct evAccept) link;
+} evAccept;
+
+typedef struct evFile {
+ evFileFunc func;
+ void * uap;
+ int fd;
+ int eventmask;
+ int preemptive;
+ struct evFile * prev;
+ struct evFile * next;
+ struct evFile * fdprev;
+ struct evFile * fdnext;
+} evFile;
+
+typedef struct evStream {
+ evStreamFunc func;
+ void * uap;
+ evFileID file;
+ evTimerID timer;
+ int flags;
+#define EV_STR_TIMEROK 0x0001 /*%< IFF timer valid. */
+ int fd;
+ struct iovec * iovOrig;
+ int iovOrigCount;
+ struct iovec * iovCur;
+ int iovCurCount;
+ int ioTotal;
+ int ioDone;
+ int ioErrno;
+ struct evStream *prevDone, *nextDone;
+ struct evStream *prev, *next;
+} evStream;
+
+typedef struct evTimer {
+ evTimerFunc func;
+ void * uap;
+ struct timespec due, inter;
+ int index;
+ int mode;
+#define EV_TMR_RATE 1
+} evTimer;
+
+typedef struct evWait {
+ evWaitFunc func;
+ void * uap;
+ const void * tag;
+ struct evWait * next;
+} evWait;
+
+typedef struct evWaitList {
+ evWait * first;
+ evWait * last;
+ struct evWaitList * prev;
+ struct evWaitList * next;
+} evWaitList;
+
+typedef struct evEvent_p {
+ enum { Accept, File, Stream, Timer, Wait, Free, Null } type;
+ union {
+ struct { evAccept *this; } accept;
+ struct { evFile *this; int eventmask; } file;
+ struct { evStream *this; } stream;
+ struct { evTimer *this; } timer;
+ struct { evWait *this; } wait;
+ struct { struct evEvent_p *next; } free;
+ struct { const void *placeholder; } null;
+ } u;
+} evEvent_p;
+
+#ifdef USE_POLL
+typedef struct {
+ void *ctx; /* pointer to the evContext_p */
+ uint32_t type; /* READ, WRITE, EXCEPT, nonblk */
+ uint32_t result; /* 1 => revents, 0 => events */
+} __evEmulMask;
+
+#define emulMaskInit(ctx, field, ev, lastnext) \
+ ctx->field.ctx = ctx; \
+ ctx->field.type = ev; \
+ ctx->field.result = lastnext;
+
+extern short *__fd_eventfield(int fd, __evEmulMask *maskp);
+extern short __poll_event(__evEmulMask *maskp);
+extern void __fd_clr(int fd, __evEmulMask *maskp);
+extern void __fd_set(int fd, __evEmulMask *maskp);
+
+#undef FD_ZERO
+#define FD_ZERO(maskp)
+
+#undef FD_SET
+#define FD_SET(fd, maskp) \
+ __fd_set(fd, maskp)
+
+#undef FD_CLR
+#define FD_CLR(fd, maskp) \
+ __fd_clr(fd, maskp)
+
+#undef FD_ISSET
+#define FD_ISSET(fd, maskp) \
+ ((*__fd_eventfield(fd, maskp) & __poll_event(maskp)) != 0)
+
+#endif /* USE_POLL */
+
+typedef struct {
+ /* Global. */
+ const evEvent_p *cur;
+ /* Debugging. */
+ int debug;
+ FILE *output;
+ /* Connections. */
+ evConn *conns;
+ LIST(evAccept) accepts;
+ /* Files. */
+ evFile *files, *fdNext;
+#ifndef USE_POLL
+ fd_set rdLast, rdNext;
+ fd_set wrLast, wrNext;
+ fd_set exLast, exNext;
+ fd_set nonblockBefore;
+ int fdMax, fdCount, highestFD;
+ evFile *fdTable[FD_SETSIZE];
+#else
+ struct pollfd *pollfds; /* Allocated as needed */
+ evFile **fdTable; /* Ditto */
+ int maxnfds; /* # elements in above */
+ int firstfd; /* First active fd */
+ int fdMax; /* Last active fd */
+ int fdCount; /* # fd:s with I/O */
+ int highestFD; /* max fd allowed by OS */
+ __evEmulMask rdLast, rdNext;
+ __evEmulMask wrLast, wrNext;
+ __evEmulMask exLast, exNext;
+ __evEmulMask nonblockBefore;
+#endif /* USE_POLL */
+#ifdef EVENTLIB_TIME_CHECKS
+ struct timespec lastSelectTime;
+ int lastFdCount;
+#endif
+ /* Streams. */
+ evStream *streams;
+ evStream *strDone, *strLast;
+ /* Timers. */
+ struct timespec lastEventTime;
+ heap_context timers;
+ /* Waits. */
+ evWaitList *waitLists;
+ evWaitList waitDone;
+} evContext_p;
+
+/* eventlib.c */
+#define evPrintf __evPrintf
+void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(3, 4);
+
+#ifdef USE_POLL
+extern int evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd);
+#endif /* USE_POLL */
+
+/* ev_timers.c */
+#define evCreateTimers __evCreateTimers
+heap_context evCreateTimers(const evContext_p *);
+#define evDestroyTimers __evDestroyTimers
+void evDestroyTimers(const evContext_p *);
+
+/* ev_waits.c */
+#define evFreeWait __evFreeWait
+evWait *evFreeWait(evContext_p *ctx, evWait *old);
+
+/* Global options */
+extern int __evOptMonoTime;
+
+#endif /*_EVENTLIB_P_H*/
diff --git a/usr/src/lib/libresolv2_joy/common/isc/heap.c b/usr/src/lib/libresolv2_joy/common/isc/heap.c
new file mode 100644
index 0000000000..3d22b6fc71
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/heap.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*%
+ * Heap implementation of priority queues adapted from the following:
+ *
+ * _Introduction to Algorithms_, Cormen, Leiserson, and Rivest,
+ * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ * _Algorithms_, Second Edition, Sedgewick, Addison-Wesley, 1988,
+ * ISBN 0-201-06673-4, chapter 11.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: heap.c,v 1.4 2006/03/09 23:57:56 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "port_after.h"
+
+#include <isc/heap.h>
+
+/*%
+ * Note: to make heap_parent and heap_left easy to compute, the first
+ * element of the heap array is not used; i.e. heap subscripts are 1-based,
+ * not 0-based.
+ */
+#define heap_parent(i) ((i) >> 1)
+#define heap_left(i) ((i) << 1)
+
+#define ARRAY_SIZE_INCREMENT 512
+
+heap_context
+heap_new(heap_higher_priority_func higher_priority, heap_index_func index,
+ int array_size_increment) {
+ heap_context ctx;
+
+ if (higher_priority == NULL)
+ return (NULL);
+
+ ctx = (heap_context)malloc(sizeof (struct heap_context));
+ if (ctx == NULL)
+ return (NULL);
+
+ ctx->array_size = 0;
+ if (array_size_increment == 0)
+ ctx->array_size_increment = ARRAY_SIZE_INCREMENT;
+ else
+ ctx->array_size_increment = array_size_increment;
+ ctx->heap_size = 0;
+ ctx->heap = NULL;
+ ctx->higher_priority = higher_priority;
+ ctx->index = index;
+ return (ctx);
+}
+
+int
+heap_free(heap_context ctx) {
+ if (ctx == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (ctx->heap != NULL)
+ free(ctx->heap);
+ free(ctx);
+
+ return (0);
+}
+
+static int
+heap_resize(heap_context ctx) {
+ void **new_heap;
+
+ ctx->array_size += ctx->array_size_increment;
+ new_heap = (void **)realloc(ctx->heap,
+ (ctx->array_size) * (sizeof (void *)));
+ if (new_heap == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ ctx->heap = new_heap;
+ return (0);
+}
+
+static void
+float_up(heap_context ctx, int i, void *elt) {
+ int p;
+
+ for ( p = heap_parent(i);
+ i > 1 && ctx->higher_priority(elt, ctx->heap[p]);
+ i = p, p = heap_parent(i) ) {
+ ctx->heap[i] = ctx->heap[p];
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+ }
+ ctx->heap[i] = elt;
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+}
+
+static void
+sink_down(heap_context ctx, int i, void *elt) {
+ int j, size, half_size;
+
+ size = ctx->heap_size;
+ half_size = size / 2;
+ while (i <= half_size) {
+ /* find smallest of the (at most) two children */
+ j = heap_left(i);
+ if (j < size && ctx->higher_priority(ctx->heap[j+1],
+ ctx->heap[j]))
+ j++;
+ if (ctx->higher_priority(elt, ctx->heap[j]))
+ break;
+ ctx->heap[i] = ctx->heap[j];
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+ i = j;
+ }
+ ctx->heap[i] = elt;
+ if (ctx->index != NULL)
+ (ctx->index)(ctx->heap[i], i);
+}
+
+int
+heap_insert(heap_context ctx, void *elt) {
+ int i;
+
+ if (ctx == NULL || elt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ i = ++ctx->heap_size;
+ if (ctx->heap_size >= ctx->array_size && heap_resize(ctx) < 0)
+ return (-1);
+
+ float_up(ctx, i, elt);
+
+ return (0);
+}
+
+int
+heap_delete(heap_context ctx, int i) {
+ void *elt;
+ int less;
+
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (i == ctx->heap_size) {
+ ctx->heap_size--;
+ } else {
+ elt = ctx->heap[ctx->heap_size--];
+ less = ctx->higher_priority(elt, ctx->heap[i]);
+ ctx->heap[i] = elt;
+ if (less)
+ float_up(ctx, i, ctx->heap[i]);
+ else
+ sink_down(ctx, i, ctx->heap[i]);
+ }
+
+ return (0);
+}
+
+int
+heap_increased(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ float_up(ctx, i, ctx->heap[i]);
+
+ return (0);
+}
+
+int
+heap_decreased(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ sink_down(ctx, i, ctx->heap[i]);
+
+ return (0);
+}
+
+void *
+heap_element(heap_context ctx, int i) {
+ if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (ctx->heap[i]);
+}
+
+int
+heap_for_each(heap_context ctx, heap_for_each_func action, void *uap) {
+ int i;
+
+ if (ctx == NULL || action == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ for (i = 1; i <= ctx->heap_size; i++)
+ (action)(ctx->heap[i], uap);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/hex.c b/usr/src/lib/libresolv2_joy/common/isc/hex.c
new file mode 100644
index 0000000000..e43be4f3b5
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/hex.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2001 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <port_before.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <isc/misc.h>
+#include <port_after.h>
+
+static const char hex[17] = "0123456789abcdef";
+
+int
+isc_gethexstring(unsigned char *buf, size_t len, int count, FILE *fp,
+ int *multiline)
+{
+ int c, n;
+ unsigned char x;
+ char *s;
+ int result = count;
+
+ x = 0; /*%< silence compiler */
+ n = 0;
+ while (count > 0) {
+ c = fgetc(fp);
+
+ if ((c == EOF) ||
+ (c == '\n' && !*multiline) ||
+ (c == '(' && *multiline) ||
+ (c == ')' && !*multiline))
+ goto formerr;
+ /* comment */
+ if (c == ';') {
+ do {
+ c = fgetc(fp);
+ } while (c != EOF && c != '\n');
+ if (c == '\n' && *multiline)
+ continue;
+ goto formerr;
+ }
+ /* white space */
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
+ continue;
+ /* multiline */
+ if ('(' == c || c == ')') {
+ *multiline = (c == '(' /*)*/);
+ continue;
+ }
+ if ((s = strchr(hex, tolower(c))) == NULL)
+ goto formerr;
+ x = (x<<4) | (s - hex);
+ if (++n == 2) {
+ if (len > 0U) {
+ *buf++ = x;
+ len--;
+ } else
+ result = -1;
+ count--;
+ n = 0;
+ }
+ }
+ return (result);
+
+ formerr:
+ if (c == '\n')
+ ungetc(c, fp);
+ return (-1);
+}
+
+void
+isc_puthexstring(FILE *fp, const unsigned char *buf, size_t buflen,
+ size_t len1, size_t len2, const char *sep)
+{
+ size_t i = 0;
+
+ if (len1 < 4U)
+ len1 = 4;
+ if (len2 < 4U)
+ len2 = 4;
+ while (buflen > 0U) {
+ fputc(hex[(buf[0]>>4)&0xf], fp);
+ fputc(hex[buf[0]&0xf], fp);
+ i += 2;
+ buflen--;
+ buf++;
+ if (i >= len1 && sep != NULL) {
+ fputs(sep, fp);
+ i = 0;
+ len1 = len2;
+ }
+ }
+}
+
+void
+isc_tohex(const unsigned char *buf, size_t buflen, char *t) {
+ while (buflen > 0U) {
+ *t++ = hex[(buf[0]>>4)&0xf];
+ *t++ = hex[buf[0]&0xf];
+ buf++;
+ buflen--;
+ }
+ *t = '\0';
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/logging.c b/usr/src/lib/libresolv2_joy/common/isc/logging.c
new file mode 100644
index 0000000000..8c2af2b9e3
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/logging.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: logging.c,v 1.9 2008/11/14 02:36:51 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/assertions.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#include "port_after.h"
+
+#include "logging_p.h"
+
+static const int syslog_priority[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+ LOG_WARNING, LOG_ERR, LOG_CRIT };
+
+static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+static const char *level_text[] = {
+ "info: ", "notice: ", "warning: ", "error: ", "critical: "
+};
+
+static void
+version_rename(log_channel chan) {
+ unsigned int ver;
+ char old_name[PATH_MAX+1];
+ char new_name[PATH_MAX+1];
+
+ ver = chan->out.file.versions;
+ if (ver < 1)
+ return;
+ if (ver > LOG_MAX_VERSIONS)
+ ver = LOG_MAX_VERSIONS;
+ /*
+ * Need to have room for '.nn' (XXX assumes LOG_MAX_VERSIONS < 100)
+ */
+ if (strlen(chan->out.file.name) > (size_t)(PATH_MAX-3))
+ return;
+ for (ver--; ver > 0; ver--) {
+ sprintf(old_name, "%s.%d", chan->out.file.name, ver-1);
+ sprintf(new_name, "%s.%d", chan->out.file.name, ver);
+ (void)isc_movefile(old_name, new_name);
+ }
+ sprintf(new_name, "%s.0", chan->out.file.name);
+ (void)isc_movefile(chan->out.file.name, new_name);
+}
+
+FILE *
+log_open_stream(log_channel chan) {
+ FILE *stream;
+ int fd, flags;
+ struct stat sb;
+ int regular;
+
+ if (chan == NULL || chan->type != log_file) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /*
+ * Don't open already open streams
+ */
+ if (chan->out.file.stream != NULL)
+ return (chan->out.file.stream);
+
+ if (stat(chan->out.file.name, &sb) < 0) {
+ if (errno != ENOENT) {
+ syslog(LOG_ERR,
+ "log_open_stream: stat of %s failed: %s",
+ chan->out.file.name, strerror(errno));
+ chan->flags |= LOG_CHANNEL_BROKEN;
+ return (NULL);
+ }
+ regular = 1;
+ } else
+ regular = (sb.st_mode & S_IFREG);
+
+ if (chan->out.file.versions) {
+ if (!regular) {
+ syslog(LOG_ERR,
+ "log_open_stream: want versions but %s isn't a regular file",
+ chan->out.file.name);
+ chan->flags |= LOG_CHANNEL_BROKEN;
+ errno = EINVAL;
+ return (NULL);
+ }
+ }
+
+ flags = O_WRONLY|O_CREAT|O_APPEND;
+
+ if ((chan->flags & LOG_TRUNCATE) != 0) {
+ if (regular) {
+ (void)unlink(chan->out.file.name);
+ flags |= O_EXCL;
+ } else {
+ syslog(LOG_ERR,
+ "log_open_stream: want truncation but %s isn't a regular file",
+ chan->out.file.name);
+ chan->flags |= LOG_CHANNEL_BROKEN;
+ errno = EINVAL;
+ return (NULL);
+ }
+ }
+
+ fd = open(chan->out.file.name, flags,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (fd < 0) {
+ syslog(LOG_ERR, "log_open_stream: open(%s) failed: %s",
+ chan->out.file.name, strerror(errno));
+ chan->flags |= LOG_CHANNEL_BROKEN;
+ return (NULL);
+ }
+ stream = fdopen(fd, "a");
+ if (stream == NULL) {
+ syslog(LOG_ERR, "log_open_stream: fdopen() failed");
+ chan->flags |= LOG_CHANNEL_BROKEN;
+ return (NULL);
+ }
+ (void) fchown(fd, chan->out.file.owner, chan->out.file.group);
+
+ chan->out.file.stream = stream;
+ return (stream);
+}
+
+int
+log_close_stream(log_channel chan) {
+ FILE *stream;
+
+ if (chan == NULL || chan->type != log_file) {
+ errno = EINVAL;
+ return (0);
+ }
+ stream = chan->out.file.stream;
+ chan->out.file.stream = NULL;
+ if (stream != NULL && fclose(stream) == EOF)
+ return (-1);
+ return (0);
+}
+
+void
+log_close_debug_channels(log_context lc) {
+ log_channel_list lcl;
+ int i;
+
+ for (i = 0; i < lc->num_categories; i++)
+ for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl->next)
+ if (lcl->channel->type == log_file &&
+ lcl->channel->out.file.stream != NULL &&
+ lcl->channel->flags & LOG_REQUIRE_DEBUG)
+ (void)log_close_stream(lcl->channel);
+}
+
+FILE *
+log_get_stream(log_channel chan) {
+ if (chan == NULL || chan->type != log_file) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (chan->out.file.stream);
+}
+
+char *
+log_get_filename(log_channel chan) {
+ if (chan == NULL || chan->type != log_file) {
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (chan->out.file.name);
+}
+
+int
+log_check_channel(log_context lc, int level, log_channel chan) {
+ int debugging, chan_level;
+
+ REQUIRE(lc != NULL);
+
+ debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
+
+ /*
+ * If not debugging, short circuit debugging messages very early.
+ */
+ if (level > 0 && !debugging)
+ return (0);
+
+ if ((chan->flags & (LOG_CHANNEL_BROKEN|LOG_CHANNEL_OFF)) != 0)
+ return (0);
+
+ /* Some channels only log when debugging is on. */
+ if ((chan->flags & LOG_REQUIRE_DEBUG) && !debugging)
+ return (0);
+
+ /* Some channels use the global level. */
+ if ((chan->flags & LOG_USE_CONTEXT_LEVEL) != 0) {
+ chan_level = lc->level;
+ } else
+ chan_level = chan->level;
+
+ if (level > chan_level)
+ return (0);
+
+ return (1);
+}
+
+int
+log_check(log_context lc, int category, int level) {
+ log_channel_list lcl;
+ int debugging;
+
+ REQUIRE(lc != NULL);
+
+ debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
+
+ /*
+ * If not debugging, short circuit debugging messages very early.
+ */
+ if (level > 0 && !debugging)
+ return (0);
+
+ if (category < 0 || category > lc->num_categories)
+ category = 0; /*%< use default */
+ lcl = lc->categories[category];
+ if (lcl == NULL) {
+ category = 0;
+ lcl = lc->categories[0];
+ }
+
+ for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
+ if (log_check_channel(lc, level, lcl->channel))
+ return (1);
+ }
+ return (0);
+}
+
+void
+log_vwrite(log_context lc, int category, int level, const char *format,
+ va_list args) {
+ log_channel_list lcl;
+ int pri, debugging, did_vsprintf = 0;
+ int original_category;
+ FILE *stream;
+ log_channel chan;
+ struct timeval tv;
+ struct tm *local_tm;
+#ifdef HAVE_TIME_R
+ struct tm tm_tmp;
+#endif
+ time_t tt;
+ const char *category_name;
+ const char *level_str;
+ char time_buf[256];
+ char level_buf[256];
+
+ REQUIRE(lc != NULL);
+
+ debugging = (lc->flags & LOG_OPTION_DEBUG);
+
+ /*
+ * If not debugging, short circuit debugging messages very early.
+ */
+ if (level > 0 && !debugging)
+ return;
+
+ if (category < 0 || category > lc->num_categories)
+ category = 0; /*%< use default */
+ original_category = category;
+ lcl = lc->categories[category];
+ if (lcl == NULL) {
+ category = 0;
+ lcl = lc->categories[0];
+ }
+
+ /*
+ * Get the current time and format it.
+ */
+ time_buf[0]='\0';
+ if (gettimeofday(&tv, NULL) < 0) {
+ syslog(LOG_INFO, "gettimeofday failed in log_vwrite()");
+ } else {
+ tt = tv.tv_sec;
+#ifdef HAVE_TIME_R
+ local_tm = localtime_r(&tt, &tm_tmp);
+#else
+ local_tm = localtime(&tt);
+#endif
+ if (local_tm != NULL) {
+ sprintf(time_buf, "%02d-%s-%4d %02d:%02d:%02d.%03ld ",
+ local_tm->tm_mday, months[local_tm->tm_mon],
+ local_tm->tm_year+1900, local_tm->tm_hour,
+ local_tm->tm_min, local_tm->tm_sec,
+ (long)tv.tv_usec/1000);
+ }
+ }
+
+ /*
+ * Make a string representation of the current category and level
+ */
+
+ if (lc->category_names != NULL &&
+ lc->category_names[original_category] != NULL)
+ category_name = lc->category_names[original_category];
+ else
+ category_name = "";
+
+ if (level >= log_critical) {
+ if (level >= 0) {
+ sprintf(level_buf, "debug %d: ", level);
+ level_str = level_buf;
+ } else
+ level_str = level_text[-level-1];
+ } else {
+ sprintf(level_buf, "level %d: ", level);
+ level_str = level_buf;
+ }
+
+ /*
+ * Write the message to channels.
+ */
+ for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
+ chan = lcl->channel;
+
+ if (!log_check_channel(lc, level, chan))
+ continue;
+
+ if (!did_vsprintf) {
+ (void)vsprintf(lc->buffer, format, args);
+ if (strlen(lc->buffer) > (size_t)LOG_BUFFER_SIZE) {
+ syslog(LOG_CRIT,
+ "memory overrun in log_vwrite()");
+ exit(1);
+ }
+ did_vsprintf = 1;
+ }
+
+ switch (chan->type) {
+ case log_syslog:
+ if (level >= log_critical)
+ pri = (level >= 0) ? 0 : -level;
+ else
+ pri = -log_critical;
+ syslog(chan->out.facility|syslog_priority[pri],
+ "%s%s%s%s",
+ (chan->flags & LOG_TIMESTAMP) ? time_buf : "",
+ (chan->flags & LOG_PRINT_CATEGORY) ?
+ category_name : "",
+ (chan->flags & LOG_PRINT_LEVEL) ?
+ level_str : "",
+ lc->buffer);
+ break;
+ case log_file:
+ stream = chan->out.file.stream;
+ if (stream == NULL) {
+ stream = log_open_stream(chan);
+ if (stream == NULL)
+ break;
+ }
+ if (chan->out.file.max_size != ULONG_MAX) {
+ long pos;
+
+ pos = ftell(stream);
+ if (pos >= 0 &&
+ (unsigned long)pos >
+ chan->out.file.max_size) {
+ /*
+ * try to roll over the log files,
+ * ignoring all all return codes
+ * except the open (we don't want
+ * to write any more anyway)
+ */
+ log_close_stream(chan);
+ version_rename(chan);
+ stream = log_open_stream(chan);
+ if (stream == NULL)
+ break;
+ }
+ }
+ fprintf(stream, "%s%s%s%s\n",
+ (chan->flags & LOG_TIMESTAMP) ? time_buf : "",
+ (chan->flags & LOG_PRINT_CATEGORY) ?
+ category_name : "",
+ (chan->flags & LOG_PRINT_LEVEL) ?
+ level_str : "",
+ lc->buffer);
+ fflush(stream);
+ break;
+ case log_null:
+ break;
+ default:
+ syslog(LOG_ERR,
+ "unknown channel type in log_vwrite()");
+ }
+ }
+}
+
+void
+log_write(log_context lc, int category, int level, const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ log_vwrite(lc, category, level, format, args);
+ va_end(args);
+}
+
+/*%
+ * Functions to create, set, or destroy contexts
+ */
+
+int
+log_new_context(int num_categories, char **category_names, log_context *lc) {
+ log_context nlc;
+
+ nlc = memget(sizeof (struct log_context));
+ if (nlc == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ nlc->num_categories = num_categories;
+ nlc->category_names = category_names;
+ nlc->categories = memget(num_categories * sizeof (log_channel_list));
+ if (nlc->categories == NULL) {
+ memput(nlc, sizeof (struct log_context));
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(nlc->categories, '\0',
+ num_categories * sizeof (log_channel_list));
+ nlc->flags = 0U;
+ nlc->level = 0;
+ *lc = nlc;
+ return (0);
+}
+
+void
+log_free_context(log_context lc) {
+ log_channel_list lcl, lcl_next;
+ log_channel chan;
+ int i;
+
+ REQUIRE(lc != NULL);
+
+ for (i = 0; i < lc->num_categories; i++)
+ for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl_next) {
+ lcl_next = lcl->next;
+ chan = lcl->channel;
+ (void)log_free_channel(chan);
+ memput(lcl, sizeof (struct log_channel_list));
+ }
+ memput(lc->categories,
+ lc->num_categories * sizeof (log_channel_list));
+ memput(lc, sizeof (struct log_context));
+}
+
+int
+log_add_channel(log_context lc, int category, log_channel chan) {
+ log_channel_list lcl;
+
+ if (lc == NULL || category < 0 || category >= lc->num_categories) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ lcl = memget(sizeof (struct log_channel_list));
+ if (lcl == NULL) {
+ errno = ENOMEM;
+ return(-1);
+ }
+ lcl->channel = chan;
+ lcl->next = lc->categories[category];
+ lc->categories[category] = lcl;
+ chan->references++;
+ return (0);
+}
+
+int
+log_remove_channel(log_context lc, int category, log_channel chan) {
+ log_channel_list lcl, prev_lcl, next_lcl;
+ int found = 0;
+
+ if (lc == NULL || category < 0 || category >= lc->num_categories) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ for (prev_lcl = NULL, lcl = lc->categories[category];
+ lcl != NULL;
+ lcl = next_lcl) {
+ next_lcl = lcl->next;
+ if (lcl->channel == chan) {
+ log_free_channel(chan);
+ if (prev_lcl != NULL)
+ prev_lcl->next = next_lcl;
+ else
+ lc->categories[category] = next_lcl;
+ memput(lcl, sizeof (struct log_channel_list));
+ /*
+ * We just set found instead of returning because
+ * the channel might be on the list more than once.
+ */
+ found = 1;
+ } else
+ prev_lcl = lcl;
+ }
+ if (!found) {
+ errno = ENOENT;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+log_option(log_context lc, int option, int value) {
+ if (lc == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ switch (option) {
+ case LOG_OPTION_DEBUG:
+ if (value)
+ lc->flags |= option;
+ else
+ lc->flags &= ~option;
+ break;
+ case LOG_OPTION_LEVEL:
+ lc->level = value;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ return (0);
+}
+
+int
+log_category_is_active(log_context lc, int category) {
+ if (lc == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (category >= 0 && category < lc->num_categories &&
+ lc->categories[category] != NULL)
+ return (1);
+ return (0);
+}
+
+log_channel
+log_new_syslog_channel(unsigned int flags, int level, int facility) {
+ log_channel chan;
+
+ chan = memget(sizeof (struct log_channel));
+ if (chan == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ chan->type = log_syslog;
+ chan->flags = flags;
+ chan->level = level;
+ chan->out.facility = facility;
+ chan->references = 0;
+ return (chan);
+}
+
+log_channel
+log_new_file_channel(unsigned int flags, int level,
+ const char *name, FILE *stream, unsigned int versions,
+ unsigned long max_size) {
+ log_channel chan;
+
+ chan = memget(sizeof (struct log_channel));
+ if (chan == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ chan->type = log_file;
+ chan->flags = flags;
+ chan->level = level;
+ if (name != NULL) {
+ size_t len;
+
+ len = strlen(name);
+ /*
+ * Quantize length to a multiple of 256. There's space for the
+ * NUL, since if len is a multiple of 256, the size chosen will
+ * be the next multiple.
+ */
+ chan->out.file.name_size = ((len / 256) + 1) * 256;
+ chan->out.file.name = memget(chan->out.file.name_size);
+ if (chan->out.file.name == NULL) {
+ memput(chan, sizeof (struct log_channel));
+ errno = ENOMEM;
+ return (NULL);
+ }
+ /* This is safe. */
+ strcpy(chan->out.file.name, name);
+ } else {
+ chan->out.file.name_size = 0;
+ chan->out.file.name = NULL;
+ }
+ chan->out.file.stream = stream;
+ chan->out.file.versions = versions;
+ chan->out.file.max_size = max_size;
+ chan->out.file.owner = getuid();
+ chan->out.file.group = getgid();
+ chan->references = 0;
+ return (chan);
+}
+
+int
+log_set_file_owner(log_channel chan, uid_t owner, gid_t group) {
+ if (chan->type != log_file) {
+ errno = EBADF;
+ return (-1);
+ }
+ chan->out.file.owner = owner;
+ chan->out.file.group = group;
+ return (0);
+}
+
+log_channel
+log_new_null_channel() {
+ log_channel chan;
+
+ chan = memget(sizeof (struct log_channel));
+ if (chan == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ chan->type = log_null;
+ chan->flags = LOG_CHANNEL_OFF;
+ chan->level = log_info;
+ chan->references = 0;
+ return (chan);
+}
+
+int
+log_inc_references(log_channel chan) {
+ if (chan == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ chan->references++;
+ return (0);
+}
+
+int
+log_dec_references(log_channel chan) {
+ if (chan == NULL || chan->references <= 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ chan->references--;
+ return (0);
+}
+
+log_channel_type
+log_get_channel_type(log_channel chan) {
+ REQUIRE(chan != NULL);
+
+ return (chan->type);
+}
+
+int
+log_free_channel(log_channel chan) {
+ if (chan == NULL || chan->references <= 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ chan->references--;
+ if (chan->references == 0) {
+ if (chan->type == log_file) {
+ if ((chan->flags & LOG_CLOSE_STREAM) &&
+ chan->out.file.stream != NULL)
+ (void)fclose(chan->out.file.stream);
+ if (chan->out.file.name != NULL)
+ memput(chan->out.file.name,
+ chan->out.file.name_size);
+ }
+ memput(chan, sizeof (struct log_channel));
+ }
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/logging_p.h b/usr/src/lib/libresolv2_joy/common/isc/logging_p.h
new file mode 100644
index 0000000000..5e6314f190
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/logging_p.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LOGGING_P_H
+#define LOGGING_P_H
+
+typedef struct log_file_desc {
+ char *name;
+ size_t name_size;
+ FILE *stream;
+ unsigned int versions;
+ unsigned long max_size;
+ uid_t owner;
+ gid_t group;
+} log_file_desc;
+
+typedef union log_output {
+ int facility;
+ log_file_desc file;
+} log_output;
+
+struct log_channel {
+ int level; /*%< don't log messages > level */
+ log_channel_type type;
+ log_output out;
+ unsigned int flags;
+ int references;
+};
+
+typedef struct log_channel_list {
+ log_channel channel;
+ struct log_channel_list *next;
+} *log_channel_list;
+
+#define LOG_BUFFER_SIZE 20480
+
+struct log_context {
+ int num_categories;
+ char **category_names;
+ log_channel_list *categories;
+ int flags;
+ int level;
+ char buffer[LOG_BUFFER_SIZE];
+};
+
+#endif /* !LOGGING_P_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/memcluster.c b/usr/src/lib/libresolv2_joy/common/isc/memcluster.c
new file mode 100644
index 0000000000..515793fd6a
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/memcluster.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/* When this symbol is defined allocations via memget are made slightly
+ bigger and some debugging info stuck before and after the region given
+ back to the caller. */
+/* #define DEBUGGING_MEMCLUSTER */
+#define MEMCLUSTER_ATEND
+
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: memcluster.c,v 1.11 2006/08/30 23:34:38 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/memcluster.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#ifdef MEMCLUSTER_RECORD
+#ifndef DEBUGGING_MEMCLUSTER
+#define DEBUGGING_MEMCLUSTER
+#endif
+#endif
+
+#define DEF_MAX_SIZE 1100
+#define DEF_MEM_TARGET 4096
+
+typedef u_int32_t fence_t;
+
+typedef struct {
+ void * next;
+#if defined(DEBUGGING_MEMCLUSTER)
+#if defined(MEMCLUSTER_RECORD)
+ const char * file;
+ int line;
+#endif
+ size_t size;
+ fence_t fencepost;
+#endif
+} memcluster_element;
+
+#define SMALL_SIZE_LIMIT sizeof(memcluster_element)
+#define P_SIZE sizeof(void *)
+#define FRONT_FENCEPOST 0xfebafeba
+#define BACK_FENCEPOST 0xabefabef
+#define FENCEPOST_SIZE 4
+
+#ifndef MEMCLUSTER_LITTLE_MALLOC
+#define MEMCLUSTER_BIG_MALLOC 1
+#define NUM_BASIC_BLOCKS 64
+#endif
+
+struct stats {
+ u_long gets;
+ u_long totalgets;
+ u_long blocks;
+ u_long freefrags;
+};
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+static pthread_mutex_t memlock = PTHREAD_MUTEX_INITIALIZER;
+#define MEMLOCK (void)pthread_mutex_lock(&memlock)
+#define MEMUNLOCK (void)pthread_mutex_unlock(&memlock)
+#else
+/*
+ * Catch bad lock usage in non threaded build.
+ */
+static unsigned int memlock = 0;
+#define MEMLOCK do { INSIST(memlock == 0); memlock = 1; } while (0)
+#define MEMUNLOCK do { INSIST(memlock == 1); memlock = 0; } while (0)
+#endif /* DO_PTHEADS */
+
+/* Private data. */
+
+static size_t max_size;
+static size_t mem_target;
+#ifndef MEMCLUSTER_BIG_MALLOC
+static size_t mem_target_half;
+static size_t mem_target_fudge;
+#endif
+static memcluster_element ** freelists;
+#ifdef MEMCLUSTER_RECORD
+static memcluster_element ** activelists;
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+static memcluster_element * basic_blocks;
+#endif
+static struct stats * stats;
+
+/* Forward. */
+
+static size_t quantize(size_t);
+#if defined(DEBUGGING_MEMCLUSTER)
+static void check(unsigned char *, int, size_t);
+#endif
+
+/* Public. */
+
+int
+meminit(size_t init_max_size, size_t target_size) {
+
+#if defined(DEBUGGING_MEMCLUSTER)
+ INSIST(sizeof(fence_t) == FENCEPOST_SIZE);
+#endif
+ if (freelists != NULL) {
+ errno = EEXIST;
+ return (-1);
+ }
+ if (init_max_size == 0U)
+ max_size = DEF_MAX_SIZE;
+ else
+ max_size = init_max_size;
+ if (target_size == 0U)
+ mem_target = DEF_MEM_TARGET;
+ else
+ mem_target = target_size;
+#ifndef MEMCLUSTER_BIG_MALLOC
+ mem_target_half = mem_target / 2;
+ mem_target_fudge = mem_target + mem_target / 4;
+#endif
+ freelists = malloc(max_size * sizeof (memcluster_element *));
+ stats = malloc((max_size+1) * sizeof (struct stats));
+ if (freelists == NULL || stats == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(freelists, 0,
+ max_size * sizeof (memcluster_element *));
+ memset(stats, 0, (max_size + 1) * sizeof (struct stats));
+#ifdef MEMCLUSTER_RECORD
+ activelists = malloc((max_size + 1) * sizeof (memcluster_element *));
+ if (activelists == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(activelists, 0,
+ (max_size + 1) * sizeof (memcluster_element *));
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+ basic_blocks = NULL;
+#endif
+ return (0);
+}
+
+void *
+__memget(size_t size) {
+ return (__memget_record(size, NULL, 0));
+}
+
+void *
+__memget_record(size_t size, const char *file, int line) {
+ size_t new_size = quantize(size);
+#if defined(DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+ char *p;
+ fence_t fp = BACK_FENCEPOST;
+#endif
+ void *ret;
+
+ MEMLOCK;
+
+#if !defined(MEMCLUSTER_RECORD)
+ UNUSED(file);
+ UNUSED(line);
+#endif
+ if (freelists == NULL) {
+ if (meminit(0, 0) == -1) {
+ MEMUNLOCK;
+ return (NULL);
+ }
+ }
+ if (size == 0U) {
+ MEMUNLOCK;
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (size >= max_size || new_size >= max_size) {
+ /* memget() was called on something beyond our upper limit. */
+ stats[max_size].gets++;
+ stats[max_size].totalgets++;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e = malloc(new_size);
+ if (e == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+ e->next = NULL;
+ e->size = size;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[max_size];
+ activelists[max_size] = e;
+#endif
+ MEMUNLOCK;
+ e->fencepost = FRONT_FENCEPOST;
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+ return ((char *)e + sizeof *e);
+#else
+ MEMUNLOCK;
+ return (malloc(size));
+#endif
+ }
+
+ /*
+ * If there are no blocks in the free list for this size, get a chunk
+ * of memory and then break it up into "new_size"-sized blocks, adding
+ * them to the free list.
+ */
+ if (freelists[new_size] == NULL) {
+ int i, frags;
+ size_t total_size;
+ void *new;
+ char *curr, *next;
+
+#ifdef MEMCLUSTER_BIG_MALLOC
+ if (basic_blocks == NULL) {
+ new = malloc(NUM_BASIC_BLOCKS * mem_target);
+ if (new == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+ curr = new;
+ next = curr + mem_target;
+ for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+ ((memcluster_element *)curr)->next = next;
+ curr = next;
+ next += mem_target;
+ }
+ /*
+ * curr is now pointing at the last block in the
+ * array.
+ */
+ ((memcluster_element *)curr)->next = NULL;
+ basic_blocks = new;
+ }
+ total_size = mem_target;
+ new = basic_blocks;
+ basic_blocks = basic_blocks->next;
+#else
+ if (new_size > mem_target_half)
+ total_size = mem_target_fudge;
+ else
+ total_size = mem_target;
+ new = malloc(total_size);
+ if (new == NULL) {
+ MEMUNLOCK;
+ errno = ENOMEM;
+ return (NULL);
+ }
+#endif
+ frags = total_size / new_size;
+ stats[new_size].blocks++;
+ stats[new_size].freefrags += frags;
+ /* Set up a linked-list of blocks of size "new_size". */
+ curr = new;
+ next = curr + new_size;
+ for (i = 0; i < (frags - 1); i++) {
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
+ ((memcluster_element *)curr)->next = next;
+ curr = next;
+ next += new_size;
+ }
+ /* curr is now pointing at the last block in the array. */
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
+ ((memcluster_element *)curr)->next = freelists[new_size];
+ freelists[new_size] = new;
+ }
+
+ /* The free list uses the "rounded-up" size "new_size". */
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = freelists[new_size];
+ ret = (char *)e + sizeof *e;
+ /*
+ * Check to see if this buffer has been written to while on free list.
+ */
+ check(ret, 0xa5, new_size - sizeof *e);
+ /*
+ * Mark memory we are returning.
+ */
+ memset(ret, 0xe5, size);
+#else
+ ret = freelists[new_size];
+#endif
+ freelists[new_size] = freelists[new_size]->next;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e->next = NULL;
+ e->size = size;
+ e->fencepost = FRONT_FENCEPOST;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[size];
+ activelists[size] = e;
+#endif
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+#endif
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ stats[size].gets++;
+ stats[size].totalgets++;
+ stats[new_size].freefrags--;
+ MEMUNLOCK;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return ((char *)e + sizeof *e);
+#else
+ return (ret);
+#endif
+}
+
+/*%
+ * This is a call from an external caller,
+ * so we want to count this as a user "put".
+ */
+void
+__memput(void *mem, size_t size) {
+ __memput_record(mem, size, NULL, 0);
+}
+
+void
+__memput_record(void *mem, size_t size, const char *file, int line) {
+ size_t new_size = quantize(size);
+#if defined (DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+ memcluster_element *el;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *prev;
+#endif
+ fence_t fp;
+ char *p;
+#endif
+
+ MEMLOCK;
+
+#if !defined (MEMCLUSTER_RECORD)
+ UNUSED(file);
+ UNUSED(line);
+#endif
+
+ REQUIRE(freelists != NULL);
+
+ if (size == 0U) {
+ MEMUNLOCK;
+ errno = EINVAL;
+ return;
+ }
+
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = (memcluster_element *) ((char *)mem - sizeof *e);
+ INSIST(e->fencepost == FRONT_FENCEPOST);
+ INSIST(e->size == size);
+ p = (char *)e + sizeof *e + size;
+ memcpy(&fp, p, sizeof fp);
+ INSIST(fp == BACK_FENCEPOST);
+ INSIST(((u_long)mem % 4) == 0);
+#ifdef MEMCLUSTER_RECORD
+ prev = NULL;
+ if (size == max_size || new_size >= max_size)
+ el = activelists[max_size];
+ else
+ el = activelists[size];
+ while (el != NULL && el != e) {
+ prev = el;
+ el = el->next;
+ }
+ INSIST(el != NULL); /*%< double free */
+ if (prev == NULL) {
+ if (size == max_size || new_size >= max_size)
+ activelists[max_size] = el->next;
+ else
+ activelists[size] = el->next;
+ } else
+ prev->next = el->next;
+#endif
+#endif
+
+ if (size == max_size || new_size >= max_size) {
+ /* memput() called on something beyond our upper limit */
+#if defined(DEBUGGING_MEMCLUSTER)
+ free(e);
+#else
+ free(mem);
+#endif
+
+ INSIST(stats[max_size].gets != 0U);
+ stats[max_size].gets--;
+ MEMUNLOCK;
+ return;
+ }
+
+ /* The free list uses the "rounded-up" size "new_size": */
+#if defined(DEBUGGING_MEMCLUSTER)
+ memset(mem, 0xa5, new_size - sizeof *e); /*%< catch write after free */
+ e->size = 0; /*%< catch double memput() */
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+#endif
+#ifdef MEMCLUSTER_ATEND
+ e->next = NULL;
+ el = freelists[new_size];
+ while (el != NULL && el->next != NULL)
+ el = el->next;
+ if (el)
+ el->next = e;
+ else
+ freelists[new_size] = e;
+#else
+ e->next = freelists[new_size];
+ freelists[new_size] = (void *)e;
+#endif
+#else
+ ((memcluster_element *)mem)->next = freelists[new_size];
+ freelists[new_size] = (memcluster_element *)mem;
+#endif
+
+ /*
+ * The stats[] uses the _actual_ "size" requested by the
+ * caller, with the caveat (in the code above) that "size" >= the
+ * max. size (max_size) ends up getting recorded as a call to
+ * max_size.
+ */
+ INSIST(stats[size].gets != 0U);
+ stats[size].gets--;
+ stats[new_size].freefrags++;
+ MEMUNLOCK;
+}
+
+void *
+__memget_debug(size_t size, const char *file, int line) {
+ void *ptr;
+ ptr = __memget_record(size, file, line);
+ fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
+ (u_long)size, ptr);
+ return (ptr);
+}
+
+void
+__memput_debug(void *ptr, size_t size, const char *file, int line) {
+ fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr,
+ (u_long)size);
+ __memput_record(ptr, size, file, line);
+}
+
+/*%
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+memstats(FILE *out) {
+ size_t i;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *e;
+#endif
+
+ MEMLOCK;
+
+ if (freelists == NULL) {
+ MEMUNLOCK;
+ return;
+ }
+ for (i = 1; i <= max_size; i++) {
+ const struct stats *s = &stats[i];
+
+ if (s->totalgets == 0U && s->gets == 0U)
+ continue;
+ fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
+ (i == max_size) ? ">=" : " ",
+ (unsigned long)i, s->totalgets, s->gets);
+ if (s->blocks != 0U)
+ fprintf(out, " (%lu bl, %lu ff)",
+ s->blocks, s->freefrags);
+ fputc('\n', out);
+ }
+#ifdef MEMCLUSTER_RECORD
+ fprintf(out, "Active Memory:\n");
+ for (i = 1; i <= max_size; i++) {
+ if ((e = activelists[i]) != NULL)
+ while (e != NULL) {
+ fprintf(out, "%s:%d %p:%lu\n",
+ e->file != NULL ? e->file :
+ "<UNKNOWN>", e->line,
+ (char *)e + sizeof *e,
+ (u_long)e->size);
+ e = e->next;
+ }
+ }
+#endif
+ MEMUNLOCK;
+}
+
+int
+memactive(void) {
+ size_t i;
+
+ if (stats == NULL)
+ return (0);
+ for (i = 1; i <= max_size; i++)
+ if (stats[i].gets != 0U)
+ return (1);
+ return (0);
+}
+
+/* Private. */
+
+/*%
+ * Round up size to a multiple of sizeof(void *). This guarantees that a
+ * block is at least sizeof void *, and that we won't violate alignment
+ * restrictions, both of which are needed to make lists of blocks.
+ */
+static size_t
+quantize(size_t size) {
+ int remainder;
+ /*
+ * If there is no remainder for the integer division of
+ *
+ * (rightsize/P_SIZE)
+ *
+ * then we already have a good size; if not, then we need
+ * to round up the result in order to get a size big
+ * enough to satisfy the request _and_ aligned on P_SIZE boundaries.
+ */
+ remainder = size % P_SIZE;
+ if (remainder != 0)
+ size += P_SIZE - remainder;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return (size + SMALL_SIZE_LIMIT + sizeof (int));
+#else
+ return (size);
+#endif
+}
+
+#if defined(DEBUGGING_MEMCLUSTER)
+static void
+check(unsigned char *a, int value, size_t len) {
+ size_t i;
+ for (i = 0; i < len; i++)
+ INSIST(a[i] == value);
+}
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/movefile.c b/usr/src/lib/libresolv2_joy/common/isc/movefile.c
new file mode 100644
index 0000000000..0ffc7047e2
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/movefile.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2000 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <port_before.h>
+#include <stdio.h>
+#include <isc/misc.h>
+#include <port_after.h>
+#ifndef HAVE_MOVEFILE
+/*
+ * rename() is lame (can't overwrite an existing file) on some systems.
+ * use movefile() instead, and let lame OS ports do what they need to.
+ */
+
+int
+isc_movefile(const char *oldname, const char *newname) {
+ return (rename(oldname, newname));
+}
+#else
+ static int os_port_has_isc_movefile = 1;
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/isc/tree.c b/usr/src/lib/libresolv2_joy/common/isc/tree.c
new file mode 100644
index 0000000000..8ba675fbe8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/isc/tree.c
@@ -0,0 +1,534 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: tree.c,v 1.4 2005/04/27 04:56:39 sra Exp $";
+#endif
+
+/*%
+ * tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+/*%
+ * This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*#define DEBUG "tree"*/
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#include <isc/memcluster.h>
+#include <isc/tree.h>
+
+#ifdef DEBUG
+static int debugDepth = 0;
+static char *debugFuncs[256];
+# define ENTER(proc) { \
+ debugFuncs[debugDepth] = proc; \
+ fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ debugDepth++; \
+ }
+# define RET(value) { \
+ debugDepth--; \
+ fprintf(stderr, "RET(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return (value); \
+ }
+# define RETV { \
+ debugDepth--; \
+ fprintf(stderr, "RETV(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return; \
+ }
+# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc) ;
+# define RET(value) return (value);
+# define RETV return;
+# define MSG(msg) ;
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+static tree * sprout(tree **, tree_t, int *, int (*)(), void (*)());
+static int delete(tree **, int (*)(), tree_t, void (*)(), int *, int *);
+static void del(tree **, int *, tree **, void (*)(), int *);
+static void bal_L(tree **, int *);
+static void bal_R(tree **, int *);
+
+void
+tree_init(tree **ppr_tree) {
+ ENTER("tree_init")
+ *ppr_tree = NULL;
+ RETV
+}
+
+tree_t
+tree_srch(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t), tree_t p_user) {
+ ENTER("tree_srch")
+
+ if (*ppr_tree) {
+ int i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+ if (i_comp > 0)
+ RET(tree_srch(&(**ppr_tree).right,
+ pfi_compare,
+ p_user))
+
+ if (i_comp < 0)
+ RET(tree_srch(&(**ppr_tree).left,
+ pfi_compare,
+ p_user))
+
+ /* not higher, not lower... this must be the one.
+ */
+ RET((**ppr_tree).data)
+ }
+
+ /* grounded. NOT found.
+ */
+ RET(NULL)
+}
+
+tree_t
+tree_add(tree **ppr_tree, int (*pfi_compare)(tree_t, tree_t),
+ tree_t p_user, void (*pfv_uar)())
+{
+ int i_balance = FALSE;
+
+ ENTER("tree_add")
+ if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+ RET(NULL)
+ RET(p_user)
+}
+
+int
+tree_delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t),
+ tree_t p_user, void (*pfv_uar)())
+{
+ int i_balance = FALSE, i_uar_called = FALSE;
+
+ ENTER("tree_delete");
+ RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+ &i_balance, &i_uar_called))
+}
+
+int
+tree_trav(tree **ppr_tree, int (*pfi_uar)(tree_t)) {
+ ENTER("tree_trav")
+
+ if (!*ppr_tree)
+ RET(TRUE)
+
+ if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+ RET(FALSE)
+ if (!(*pfi_uar)((**ppr_tree).data))
+ RET(FALSE)
+ if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+ RET(FALSE)
+ RET(TRUE)
+}
+
+void
+tree_mung(tree **ppr_tree, void (*pfv_uar)(tree_t)) {
+ ENTER("tree_mung")
+ if (*ppr_tree) {
+ tree_mung(&(**ppr_tree).left, pfv_uar);
+ tree_mung(&(**ppr_tree).right, pfv_uar);
+ if (pfv_uar)
+ (*pfv_uar)((**ppr_tree).data);
+ memput(*ppr_tree, sizeof(tree));
+ *ppr_tree = NULL;
+ }
+ RETV
+}
+
+static tree *
+sprout(tree **ppr, tree_t p_data, int *pi_balance,
+ int (*pfi_compare)(tree_t, tree_t), void (*pfv_delete)(tree_t))
+{
+ tree *p1, *p2, *sub;
+ int cmp;
+
+ ENTER("sprout")
+
+ /* are we grounded? if so, add the node "here" and set the rebalance
+ * flag, then exit.
+ */
+ if (!*ppr) {
+ MSG("grounded. adding new node, setting h=true")
+ *ppr = (tree *) memget(sizeof(tree));
+ if (*ppr) {
+ (*ppr)->left = NULL;
+ (*ppr)->right = NULL;
+ (*ppr)->bal = 0;
+ (*ppr)->data = p_data;
+ *pi_balance = TRUE;
+ }
+ RET(*ppr);
+ }
+
+ /* compare the data using routine passed by caller.
+ */
+ cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+ /* if LESS, prepare to move to the left.
+ */
+ if (cmp < 0) {
+ MSG("LESS. sprouting left.")
+ sub = sprout(&(*ppr)->left, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) { /*%< left branch has grown */
+ MSG("LESS: left branch has grown")
+ switch ((*ppr)->bal) {
+ case 1:
+ /* right branch WAS longer; bal is ok now */
+ MSG("LESS: case 1.. bal restored implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ /* balance WAS okay; now left branch longer */
+ MSG("LESS: case 0.. balnce bad but still ok")
+ (*ppr)->bal = -1;
+ break;
+ case -1:
+ /* left branch was already too long. rebal */
+ MSG("LESS: case -1: rebalancing")
+ p1 = (*ppr)->left;
+ if (p1->bal == -1) { /*%< LL */
+ MSG("LESS: single LL")
+ (*ppr)->left = p1->right;
+ p1->right = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /*%< double LR */
+ MSG("LESS: double LR")
+
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+
+ (*ppr)->left = p2->right;
+ p2->right = *ppr;
+
+ if (p2->bal == -1)
+ (*ppr)->bal = 1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* if MORE, prepare to move to the right.
+ */
+ if (cmp > 0) {
+ MSG("MORE: sprouting to the right")
+ sub = sprout(&(*ppr)->right, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) {
+ MSG("MORE: right branch has grown")
+
+ switch ((*ppr)->bal) {
+ case -1:
+ MSG("MORE: balance was off, fixed implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ MSG("MORE: balance was okay, now off but ok")
+ (*ppr)->bal = 1;
+ break;
+ case 1:
+ MSG("MORE: balance was off, need to rebalance")
+ p1 = (*ppr)->right;
+ if (p1->bal == 1) { /*%< RR */
+ MSG("MORE: single RR")
+ (*ppr)->right = p1->left;
+ p1->left = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /*%< double RL */
+ MSG("MORE: double RL")
+
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+
+ (*ppr)->right = p2->left;
+ p2->left = *ppr;
+
+ if (p2->bal == 1)
+ (*ppr)->bal = -1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* not less, not more: this is the same key! replace...
+ */
+ MSG("FOUND: Replacing data value")
+ *pi_balance = FALSE;
+ if (pfv_delete)
+ (*pfv_delete)((*ppr)->data);
+ (*ppr)->data = p_data;
+ RET(*ppr)
+}
+
+static int
+delete(tree **ppr_p, int (*pfi_compare)(tree_t, tree_t), tree_t p_user,
+ void (*pfv_uar)(tree_t), int *pi_balance, int *pi_uar_called)
+{
+ tree *pr_q;
+ int i_comp, i_ret;
+
+ ENTER("delete")
+
+ if (*ppr_p == NULL) {
+ MSG("key not in tree")
+ RET(FALSE)
+ }
+
+ i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+ if (i_comp > 0) {
+ MSG("too high - scan left")
+ i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ } else if (i_comp < 0) {
+ MSG("too low - scan right")
+ i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_p, pi_balance);
+ } else {
+ MSG("equal")
+ pr_q = *ppr_p;
+ if (pr_q->right == NULL) {
+ MSG("right subtree null")
+ *ppr_p = pr_q->left;
+ *pi_balance = TRUE;
+ } else if (pr_q->left == NULL) {
+ MSG("right subtree non-null, left subtree null")
+ *ppr_p = pr_q->right;
+ *pi_balance = TRUE;
+ } else {
+ MSG("neither subtree null")
+ del(&pr_q->left, pi_balance, &pr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ }
+ if (!*pi_uar_called && pfv_uar)
+ (*pfv_uar)(pr_q->data);
+ /* Thanks to wuth@castrov.cuc.ab.ca for the following stmt. */
+ memput(pr_q, sizeof(tree));
+ i_ret = TRUE;
+ }
+ RET(i_ret)
+}
+
+static void
+del(tree **ppr_r, int *pi_balance, tree **ppr_q,
+ void (*pfv_uar)(tree_t), int *pi_uar_called)
+{
+ ENTER("del")
+
+ if ((*ppr_r)->right != NULL) {
+ del(&(*ppr_r)->right, pi_balance, ppr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_r, pi_balance);
+ } else {
+ if (pfv_uar)
+ (*pfv_uar)((*ppr_q)->data);
+ *pi_uar_called = TRUE;
+ (*ppr_q)->data = (*ppr_r)->data;
+ *ppr_q = *ppr_r;
+ *ppr_r = (*ppr_r)->left;
+ *pi_balance = TRUE;
+ }
+
+ RETV
+}
+
+static void
+bal_L(tree **ppr_p, int *pi_balance) {
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_L")
+ MSG("left branch has shrunk")
+
+ switch ((*ppr_p)->bal) {
+ case -1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = 1;
+ *pi_balance = FALSE;
+ break;
+ case 1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->right;
+ b1 = p1->bal;
+ if (b1 >= 0) {
+ MSG("single RR")
+ (*ppr_p)->right = p1->left;
+ p1->left = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = 1;
+ p1->bal = -1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double RL")
+ p2 = p1->left;
+ b2 = p2->bal;
+ p1->left = p2->right;
+ p2->right = p1;
+ (*ppr_p)->right = p2->left;
+ p2->left = *ppr_p;
+ if (b2 == 1)
+ (*ppr_p)->bal = -1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+static void
+bal_R(tree **ppr_p, int *pi_balance) {
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_R")
+ MSG("right branch has shrunk")
+ switch ((*ppr_p)->bal) {
+ case 1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = -1;
+ *pi_balance = FALSE;
+ break;
+ case -1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->left;
+ b1 = p1->bal;
+ if (b1 <= 0) {
+ MSG("single LL")
+ (*ppr_p)->left = p1->right;
+ p1->right = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = -1;
+ p1->bal = 1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double LR")
+ p2 = p1->right;
+ b2 = p2->bal;
+ p1->right = p2->left;
+ p2->left = p1;
+ (*ppr_p)->left = p2->right;
+ p2->right = *ppr_p;
+ if (b2 == -1)
+ (*ppr_p)->bal = 1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/llib-lresolv_joy b/usr/src/lib/libresolv2_joy/common/llib-lresolv_joy
new file mode 100644
index 0000000000..aedd06a0fa
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/llib-lresolv_joy
@@ -0,0 +1,59 @@
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+/*
+ * usr/src/lib/libresolv2 routines
+ */
+
+int dn_skipname(const uchar_t *, const uchar_t *);
+void fp_query(const u_char *, FILE *);
+const uchar_t * p_cdname(const uchar_t *, const uchar_t *, FILE *);
+const char * p_class(int);
+void p_query(const u_char *);
+const char * p_time(unsigned int);
+const char * p_type(int);
+void putlong(unsigned int, uchar_t *);
+uint32_t _getlong(const u_char *);
+uint16_t _getshort(const u_char *);
+const char * hstrerror(int);
+int res_init(void);
+int res_mkquery(int, const char *, int, int, const u_char *,
+ int, const u_char *, u_char *, int);
+int res_query(const char *, int, int, u_char *, int);
+int res_querydomain(const char *, const char *, int, int,
+ u_char *, int);
+int res_search(const char *, int, int, u_char *, int);
+int res_send(const u_char *, int, u_char *, int);
+int res_update(ns_updrec *);
+int res_ninit(res_state);
+void fp_resstat(const res_state, FILE *);
+const char * res_hostalias(const res_state, const char *, char *, size_t);
+int res_nquery(res_state, const char *, int, int, u_char *, int);
+int res_nsearch(res_state, const char *, int, int, u_char *, int);
+int res_nquerydomain(res_state, const char *, const char *,
+ int, int, u_char *, int);
+int res_nmkquery(res_state, int, const char *, int, int,
+ const u_char *, int, const u_char *,
+ u_char *, int);
+int res_nsend(res_state, const u_char *, int, u_char *, int);
+int res_nmkupdate(res_state, ns_updrec *, u_char *, int);
+void res_nclose(res_state);
+int res_nsendsigned(res_state, const u_char *, int, ns_tsig_key *,
+ u_char *, int);
+int dn_comp(const char *, u_char *, int, u_char **, u_char **);
+int dn_expand(const u_char *, const u_char *, const u_char *,
+ char *, int);
diff --git a/usr/src/lib/libresolv2_joy/common/mapfile-vers b/usr/src/lib/libresolv2_joy/common/mapfile-vers
new file mode 100644
index 0000000000..e0c66a1c96
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/mapfile-vers
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ joy_dn_expand;
+ joy_res_nsearch;
+ joy_res_ninit;
+ joy_res_ndestroy;
+ joy_res_gethostbyaddr;
+ joy_res_gethostbyname;
+ joy_res_gethostbyname2;
+ joy_res_sethostent;
+ joy_res_endhostent;
+ __joy_res_override_retry;
+ __joy_res_unset_no_hosts_fallback;
+ __joy_res_set_no_hosts_fallback;
+ __joy_h_errno;
+ __joy_ns_get16;
+ __joy_ns_get32;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_date.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_date.c
new file mode 100644
index 0000000000..292375af63
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_date.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_date.c,v 1.6 2005/04/27 04:56:39 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int datepart(const char *, int, int, int, int *);
+
+/* Public. */
+
+/*%
+ * Convert a date in ASCII into the number of seconds since
+ * 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all
+ * digits required, no spaces allowed.
+ */
+
+u_int32_t
+ns_datetosecs(const char *cp, int *errp) {
+ struct tm time;
+ u_int32_t result;
+ int mdays, i;
+ static const int days_per_month[12] =
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if (strlen(cp) != 14U) {
+ *errp = 1;
+ return (0);
+ }
+ *errp = 0;
+
+ memset(&time, 0, sizeof time);
+ time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900;
+ time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1;
+ time.tm_mday = datepart(cp + 6, 2, 01, 31, errp);
+ time.tm_hour = datepart(cp + 8, 2, 00, 23, errp);
+ time.tm_min = datepart(cp + 10, 2, 00, 59, errp);
+ time.tm_sec = datepart(cp + 12, 2, 00, 59, errp);
+ if (*errp) /*%< Any parse errors? */
+ return (0);
+
+ /*
+ * OK, now because timegm() is not available in all environments,
+ * we will do it by hand. Roll up sleeves, curse the gods, begin!
+ */
+
+#define SECS_PER_DAY ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+ result = time.tm_sec; /*%< Seconds */
+ result += time.tm_min * 60; /*%< Minutes */
+ result += time.tm_hour * (60*60); /*%< Hours */
+ result += (time.tm_mday - 1) * SECS_PER_DAY; /*%< Days */
+ /* Months are trickier. Look without leaping, then leap */
+ mdays = 0;
+ for (i = 0; i < time.tm_mon; i++)
+ mdays += days_per_month[i];
+ result += mdays * SECS_PER_DAY; /*%< Months */
+ if (time.tm_mon > 1 && isleap(1900+time.tm_year))
+ result += SECS_PER_DAY; /*%< Add leapday for this year */
+ /* First figure years without leapdays, then add them in. */
+ /* The loop is slow, FIXME, but simple and accurate. */
+ result += (time.tm_year - 70) * (SECS_PER_DAY*365); /*%< Years */
+ for (i = 70; i < time.tm_year; i++)
+ if (isleap(1900+i))
+ result += SECS_PER_DAY; /*%< Add leapday for prev year */
+ return (result);
+}
+
+/* Private. */
+
+/*%
+ * Parse part of a date. Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(const char *buf, int size, int min, int max, int *errp) {
+ int result = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!isdigit((unsigned char)(buf[i])))
+ *errp = 1;
+ result = (result * 10) + buf[i] - '0';
+ }
+ if (result < min)
+ *errp = 1;
+ if (result > max)
+ *errp = 1;
+ return (result);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_name.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_name.c
new file mode 100644
index 0000000000..f6b0accef1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_name.c
@@ -0,0 +1,1153 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
+
+/* Data. */
+
+static const char digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* Forward. */
+
+static int special(int);
+static int printable(int);
+static int dn_find(const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *);
+static int encode_bitsring(const char **, const char *,
+ unsigned char **, unsigned char **,
+ unsigned const char *);
+static int labellen(const u_char *);
+static int decode_bitstring(const unsigned char **,
+ char *, const char *);
+
+/* Public. */
+
+/*%
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li The root is returned as "."
+ *\li All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ int m;
+
+ if (n != DNS_LABELTYPE_BITSTRING) {
+ /* XXX: labellen should reject this case */
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((m = decode_bitstring(&cp, dn, eom)) < 0)
+ {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ dn += m;
+ continue;
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ *
+ * return:
+ *
+ *\li -1 if it fails
+ *\li 1 if string was fully qualified
+ *\li 0 is string was not fully qualified
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
+ return (ns_name_pton2(src, dst, dstsiz, NULL));
+}
+
+/*
+ * ns_name_pton2(src, dst, dstsiz, *dstlen)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * side effects:
+ * fills in *dstlen (if non-NULL)
+ * notes:
+ * Enforces label and domain length limits.
+ */
+int
+ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) {
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /*%< start a bit string label */
+ if ((cp = strchr(src, ']')) == NULL) {
+ errno = EINVAL; /*%< ??? */
+ return (-1);
+ }
+ if ((e = encode_bitsring(&src, cp + 2,
+ &label, &bp, eom))
+ != 0) {
+ errno = e;
+ return (-1);
+ }
+ escaped = 0;
+ label = bp++;
+ if ((c = *src++) == 0)
+ goto done;
+ else if (c != '.') {
+ errno = EINVAL;
+ return (-1);
+ }
+ continue;
+ }
+ else if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
+ return (1);
+ }
+ if (c == 0 || *src == '.') {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ done:
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /*%< src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
+ return (0);
+}
+
+/*%
+ * Convert a network strings labels into all lowercase.
+ *
+ * return:
+ *\li Number of bytes written to buffer, or -1 (with errno set)
+ *
+ * notes:
+ *\li Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
+{
+ const u_char *cp;
+ u_char *dn, *eom;
+ u_char c;
+ u_int n;
+ int l;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = n;
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for ((void)NULL; l > 0; l--) {
+ c = *cp++;
+ if (isascii(c) && isupper(c))
+ *dn++ = tolower(c);
+ else
+ *dn++ = c;
+ }
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*%
+ * Unpack a domain name from a message, source may be compressed.
+ *
+ * return:
+ *\li -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz)
+{
+ return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL));
+}
+
+/*
+ * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ * side effect:
+ * fills in *dstlen (if non-NULL).
+ */
+int
+ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz, size_t *dstlen)
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, len, checked, l;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ case NS_TYPE_ELT:
+ /* Limit checks. */
+ if ((l = labellen(srcp - 1)) < 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += l + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, l);
+ dstp += l;
+ srcp += l;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+ if (srcp < msg || srcp >= eom) { /*%< Out of range. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += 2;
+ /*
+ * Check for loops in the compressed name;
+ * if we've looked at the whole message,
+ * there must be a loop.
+ */
+ if (checked >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /*%< flag error */
+ }
+ }
+ *dstp++ = 0;
+ if (dstlen != NULL)
+ *dstlen = dstp - dst;
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*%
+ * Pack domain name 'domain' into 'comp_dn'.
+ *
+ * return:
+ *\li Size of the compressed name, or -1.
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ *\li 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ *
+ * Side effects:
+ *\li The list of pointers in dnptrs is updated for labels inserted into
+ * the message as we compress the name. If 'dnptr' is NULL, we don't
+ * try to compress names. If 'lastdnptr' is NULL, we don't update the
+ * list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ (void)NULL;
+ lpp = cpp; /*%< end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if ((l0 = labellen(srcp)) < 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+ l += l0 + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+ *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+ memcpy(dstp, srcp, n + 1);
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*%
+ * Expand compressed domain name to presentation format.
+ *
+ * return:
+ *\li Number of bytes read out of `src', or -1 (with errno set).
+ *
+ * note:
+ *\li Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, size_t dstsiz)
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*%
+ * Compress a domain name into wire format, using compression pointers.
+ *
+ * return:
+ *\li Number of bytes consumed in `dst' or -1 (with errno set).
+ *
+ * notes:
+ *\li 'dnptrs' is an array of pointers to previous compressed names.
+ *\li dnptrs[0] is a pointer to the beginning of the message.
+ *\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the
+ * array pointed to by 'dnptrs'. Side effect is to update the list of
+ * pointers for labels inserted into the message as we compress the name.
+ *\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+ const u_char **dnptrs, const u_char **lastdnptr)
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*%
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+ const u_char **lastdnptr)
+{
+ while (dnptrs < lastdnptr && *dnptrs != NULL) {
+ if (*dnptrs >= src) {
+ *dnptrs = NULL;
+ break;
+ }
+ dnptrs++;
+ }
+}
+
+/*%
+ * Advance *ptrptr to skip over the compressed name it points at.
+ *
+ * return:
+ *\li 0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom)
+{
+ const u_char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /*%< EDNS0 extended label */
+ if ((l = labellen(cp - 1)) < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return (-1);
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp++;
+ break;
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Find the number of octets an nname takes up, including the root label.
+ * (This is basically ns_name_skip() without compression-pointer support.)
+ * ((NOTE: can only return zero if passed-in namesiz argument is zero.))
+ */
+ssize_t
+ns_name_length(ns_nname_ct nname, size_t namesiz) {
+ ns_nname_ct orig = nname;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ }
+ return (nname - orig);
+}
+
+/* Compare two nname's for equality. Return -1 on error (setting errno).
+ */
+int
+ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) {
+ ns_nname_ct ae = a + as, be = b + bs;
+ int ac, bc;
+
+ while (ac = *a, bc = *b, ac != 0 && bc != 0) {
+ if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (a + ac >= ae || b + bc >= be) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ac != bc || strncasecmp((const char *) ++a,
+ (const char *) ++b, ac) != 0)
+ return (0);
+ a += ac, b += bc;
+ }
+ return (ac == 0 && bc == 0);
+}
+
+/* Is domain "A" owned by (at or below) domain "B"?
+ */
+int
+ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) {
+ /* If A is shorter, it cannot be owned by B. */
+ if (an < bn)
+ return (0);
+
+ /* If they are unequal before the length of the shorter, A cannot... */
+ while (bn > 0) {
+ if (a->len != b->len ||
+ strncasecmp((const char *) a->base,
+ (const char *) b->base, a->len) != 0)
+ return (0);
+ a++, an--;
+ b++, bn--;
+ }
+
+ /* A might be longer or not, but either way, B owns it. */
+ return (1);
+}
+
+/* Build an array of <base,len> tuples from an nname, top-down order.
+ * Return the number of tuples (labels) thus discovered.
+ */
+int
+ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) {
+ u_int n;
+ int l;
+
+ n = *nname++;
+ namelen--;
+
+ /* Root zone? */
+ if (n == 0) {
+ /* Extra data follows name? */
+ if (namelen > 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+ }
+
+ /* Compression pointer? */
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+
+ /* Label too long? */
+ if (n > namelen) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+
+ /* Recurse to get rest of name done first. */
+ l = ns_name_map(nname + n, namelen - n, map, mapsize);
+ if (l < 0)
+ return (-1);
+
+ /* Too many labels? */
+ if (l >= mapsize) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ /* We're on our way back up-stack, store current map data. */
+ map[l].base = nname;
+ map[l].len = n;
+ return (l + 1);
+}
+
+/* Count the labels in a domain name. Root counts, so COM. has two. This
+ * is to make the result comparable to the result of ns_name_map().
+ */
+int
+ns_name_labels(ns_nname_ct nname, size_t namesiz) {
+ int ret = 0;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ ret++;
+ }
+ return (ret + 1);
+}
+
+/* Private. */
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+special(int ch) {
+ switch (ch) {
+ case 0x22: /*%< '"' */
+ case 0x2E: /*%< '.' */
+ case 0x3B: /*%< ';' */
+ case 0x5C: /*%< '\\' */
+ case 0x28: /*%< '(' */
+ case 0x29: /*%< ')' */
+ /* Special modifiers in zone files. */
+ case 0x40: /*%< '@' */
+ case 0x24: /*%< '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ *
+ * return:
+ *\li boolean.
+ */
+static int
+printable(int ch) {
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*%
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*%
+ * Search for the counted-label name in an array of compressed names.
+ *
+ * return:
+ *\li offset from msg if found, or -1.
+ *
+ * notes:
+ *\li dnptrs is the pointer to the first name on the list,
+ *\li not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+ const u_char * const *dnptrs,
+ const u_char * const *lastdnptr)
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ n = labellen(cp - 1); /*%< XXX */
+ if (n != *dn++)
+ goto next;
+
+ for ((void)NULL; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ sp += *sp + 1;
+ }
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+static int
+decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
+{
+ const unsigned char *cp = *cpp;
+ char *beg = dn, tc;
+ int b, blen, plen, i;
+
+ if ((blen = (*cp & 0xff)) == 0)
+ blen = 256;
+ plen = (blen + 3) / 4;
+ plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+ if (dn + plen >= eom)
+ return (-1);
+
+ cp++;
+ i = SPRINTF((dn, "\\[x"));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ for (b = blen; b > 7; b -= 8, cp++) {
+ i = SPRINTF((dn, "%02x", *cp & 0xff));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ if (b > 4) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ } else if (b > 0) {
+ tc = *cp++;
+ i = SPRINTF((dn, "%1x",
+ ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
+ if (i < 0)
+ return (-1);
+ dn += i;
+ }
+ i = SPRINTF((dn, "/%d]", blen));
+ if (i < 0)
+ return (-1);
+ dn += i;
+
+ *cpp = cp;
+ return (dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
+ unsigned char ** dst, unsigned const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ char c;
+ const char *beg_blen;
+ char *end_blen = NULL;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = end_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return (EINVAL);
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return (EINVAL);
+ if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
+ return (EINVAL);
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ switch((c = *cp)) {
+ case ']': /*%< end of the bitstring */
+ if (afterslash) {
+ if (beg_blen == NULL)
+ return (EINVAL);
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return (EINVAL);
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /*%< skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!isdigit(c&0xff))
+ return (EINVAL);
+ if (beg_blen == NULL) {
+
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return (EINVAL);
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!isxdigit(c&0xff))
+ return (EINVAL);
+ value <<= 4;
+ value += digitvalue[(int)c];
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return (EINVAL);
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return (EMSGSIZE);
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return (EINVAL);
+ traillen = tbcount - blen; /*%< between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return (EINVAL);
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return (0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+ int bitlen;
+ u_char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return (-1);
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ if ((bitlen = *(lp + 1)) == 0)
+ bitlen = 256;
+ return ((bitlen + 7 ) / 8 + 1);
+ }
+ return (-1); /*%< unknwon ELT */
+ }
+ return (l);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_netint.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_netint.c
new file mode 100644
index 0000000000..e196217f9b
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_netint.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include "port_after.h"
+
+#pragma redefine_extname __ns_get16 __joy_ns_get16
+#pragma redefine_extname __ns_get32 __joy_ns_get32
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+ u_int dst;
+
+ NS_GET16(dst, src);
+ return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+ u_long dst;
+
+ NS_GET32(dst, src);
+ return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+ NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+ NS_PUT32(src, dst);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_newmsg.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_newmsg.c
new file mode 100644
index 0000000000..c18dd060e1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_newmsg.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_newmsg.c,v 1.3 2009/02/26 10:48:57 marka Exp $";
+#endif
+
+#include <port_before.h>
+
+#include <arpa/nameser.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <port_after.h>
+
+static int rdcpy(ns_newmsg *, ns_type, const u_char *, size_t);
+
+/* Initialize a "newmsg" object to empty.
+ */
+int
+ns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *handle) {
+ ns_msg *msg = &handle->msg;
+
+ memset(handle, 0, sizeof *handle);
+ msg->_msg = buffer;
+ msg->_eom = buffer + bufsiz;
+ msg->_sect = ns_s_qd;
+ msg->_rrnum = 0;
+ msg->_msg_ptr = buffer + NS_HFIXEDSZ;
+ handle->dnptrs[0] = msg->_msg;
+ handle->dnptrs[1] = NULL;
+ handle->lastdnptr = &handle->dnptrs[sizeof handle->dnptrs /
+ sizeof handle->dnptrs[0] - 1];
+ return (0);
+}
+
+/* Initialize a "newmsg" object by copying an existing parsed message.
+ */
+int
+ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
+ ns_flag flag;
+ ns_sect sect;
+
+ ns_newmsg_id(handle, ns_msg_id(*msg));
+ for (flag = ns_f_qr; flag < ns_f_max; flag++)
+ ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
+ for (sect = ns_s_qd; sect < ns_s_max; sect++) {
+ int i, count;
+
+ count = ns_msg_count(*msg, sect);
+ for (i = 0; i < count; i++) {
+ ns_rr2 rr;
+ int x;
+
+ if (ns_parserr2(msg, sect, i, &rr) < 0)
+ return (-1);
+ if (sect == ns_s_qd)
+ x = ns_newmsg_q(handle,
+ ns_rr_nname(rr),
+ ns_rr_type(rr),
+ ns_rr_class(rr));
+ else
+ x = ns_newmsg_rr(handle, sect,
+ ns_rr_nname(rr),
+ ns_rr_type(rr),
+ ns_rr_class(rr),
+ ns_rr_ttl(rr),
+ ns_rr_rdlen(rr),
+ ns_rr_rdata(rr));
+ if (x < 0)
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/* Set the message-ID in a "newmsg" object.
+ */
+void
+ns_newmsg_id(ns_newmsg *handle, u_int16_t id) {
+ ns_msg *msg = &handle->msg;
+
+ msg->_id = id;
+}
+
+/* Set a flag (including rcode or opcode) in a "newmsg" object.
+ */
+void
+ns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value) {
+ extern struct _ns_flagdata _ns_flagdata[16];
+ struct _ns_flagdata *fd = &_ns_flagdata[flag];
+ ns_msg *msg = &handle->msg;
+
+ assert(flag < ns_f_max);
+ msg->_flags &= (~fd->mask);
+ msg->_flags |= (value << fd->shift);
+}
+
+/* Add a question (or zone, if it's an update) to a "newmsg" object.
+ */
+int
+ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname,
+ ns_type qtype, ns_class qclass)
+{
+ ns_msg *msg = &handle->msg;
+ u_char *t;
+ int n;
+
+ if (msg->_sect != ns_s_qd) {
+ errno = ENODEV;
+ return (-1);
+ }
+ t = (u_char *) (unsigned long) msg->_msg_ptr;
+ if (msg->_rrnum == 0)
+ msg->_sections[ns_s_qd] = t;
+ n = ns_name_pack(qname, t, msg->_eom - t,
+ handle->dnptrs, handle->lastdnptr);
+ if (n < 0)
+ return (-1);
+ t += n;
+ if (t + QFIXEDSZ >= msg->_eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ NS_PUT16(qtype, t);
+ NS_PUT16(qclass, t);
+ msg->_msg_ptr = t;
+ msg->_counts[ns_s_qd] = ++msg->_rrnum;
+ return (0);
+}
+
+/* Add an RR to a "newmsg" object.
+ */
+int
+ns_newmsg_rr(ns_newmsg *handle, ns_sect sect,
+ ns_nname_ct name, ns_type type,
+ ns_class rr_class, u_int32_t ttl,
+ u_int16_t rdlen, const u_char *rdata)
+{
+ ns_msg *msg = &handle->msg;
+ u_char *t;
+ int n;
+
+ if (sect < msg->_sect) {
+ errno = ENODEV;
+ return (-1);
+ }
+ t = (u_char *) (unsigned long) msg->_msg_ptr;
+ if (sect > msg->_sect) {
+ msg->_sect = sect;
+ msg->_sections[sect] = t;
+ msg->_rrnum = 0;
+ }
+ n = ns_name_pack(name, t, msg->_eom - t,
+ handle->dnptrs, handle->lastdnptr);
+ if (n < 0)
+ return (-1);
+ t += n;
+ if (t + RRFIXEDSZ + rdlen >= msg->_eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ NS_PUT16(type, t);
+ NS_PUT16(rr_class, t);
+ NS_PUT32(ttl, t);
+ msg->_msg_ptr = t;
+ if (rdcpy(handle, type, rdata, rdlen) < 0)
+ return (-1);
+ msg->_counts[sect] = ++msg->_rrnum;
+ return (0);
+}
+
+/* Complete a "newmsg" object and return its size for use in write().
+ * (Note: the "newmsg" object is also made ready for ns_parserr() etc.)
+ */
+size_t
+ns_newmsg_done(ns_newmsg *handle) {
+ ns_msg *msg = &handle->msg;
+ ns_sect sect;
+ u_char *t;
+
+ t = (u_char *) (unsigned long) msg->_msg;
+ NS_PUT16(msg->_id, t);
+ NS_PUT16(msg->_flags, t);
+ for (sect = 0; sect < ns_s_max; sect++)
+ NS_PUT16(msg->_counts[sect], t);
+ msg->_eom = msg->_msg_ptr;
+ msg->_sect = ns_s_max;
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ return (msg->_eom - msg->_msg);
+}
+
+/* Private. */
+
+/* Copy an RDATA, using compression pointers where RFC1035 permits.
+ */
+static int
+rdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) {
+ ns_msg *msg = &handle->msg;
+ u_char *p = (u_char *) (unsigned long) msg->_msg_ptr;
+ u_char *t = p + NS_INT16SZ;
+ u_char *s = t;
+ int n;
+
+ switch (type) {
+ case ns_t_soa:
+ /* MNAME. */
+ n = ns_name_pack(rdata, t, msg->_eom - t,
+ handle->dnptrs, handle->lastdnptr);
+ if (n < 0)
+ return (-1);
+ t += n;
+ if (ns_name_skip(&rdata, msg->_eom) < 0)
+ return (-1);
+
+ /* ANAME. */
+ n = ns_name_pack(rdata, t, msg->_eom - t,
+ handle->dnptrs, handle->lastdnptr);
+ if (n < 0)
+ return (-1);
+ t += n;
+ if (ns_name_skip(&rdata, msg->_eom) < 0)
+ return (-1);
+
+ /* Serial, Refresh, Retry, Expiry, and Minimum. */
+ if ((msg->_eom - t) < (NS_INT32SZ * 5)) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ memcpy(t, rdata, NS_INT32SZ * 5);
+ t += (NS_INT32SZ * 5);
+ break;
+ case ns_t_ptr:
+ case ns_t_cname:
+ case ns_t_ns:
+ /* PTRDNAME, CNAME, or NSDNAME. */
+ n = ns_name_pack(rdata, t, msg->_eom - t,
+ handle->dnptrs, handle->lastdnptr);
+ if (n < 0)
+ return (-1);
+ t += n;
+ break;
+ default:
+ memcpy(t, rdata, rdlen);
+ t += rdlen;
+ }
+ NS_PUT16(t - s, p);
+ msg->_msg_ptr = t;
+ return (0);
+}
+
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_parse.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_parse.c
new file mode 100644
index 0000000000..ba11eea707
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_parse.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#if !defined(SOLARIS2) || defined(__COVERITY__)
+#define RETERR(err) do { errno = (err); return (-1); } while (0)
+#else
+#define RETERR(err) \
+ do { errno = (err); if (errno == errno) return (-1); } while (0)
+#endif
+
+#define PARSE_FMT_PRESO 0 /* Parse using presentation-format names */
+#define PARSE_FMT_WIRE 1 /* Parse using network-format names */
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /*%< qr. */
+ { 0x7800, 11 }, /*%< opcode. */
+ { 0x0400, 10 }, /*%< aa. */
+ { 0x0200, 9 }, /*%< tc. */
+ { 0x0100, 8 }, /*%< rd. */
+ { 0x0080, 7 }, /*%< ra. */
+ { 0x0040, 6 }, /*%< z. */
+ { 0x0020, 5 }, /*%< ad. */
+ { 0x0010, 4 }, /*%< cd. */
+ { 0x000f, 0 }, /*%< rcode. */
+ { 0x0000, 0 }, /*%< expansion (1/6). */
+ { 0x0000, 0 }, /*%< expansion (2/6). */
+ { 0x0000, 0 }, /*%< expansion (3/6). */
+ { 0x0000, 0 }, /*%< expansion (4/6). */
+ { 0x0000, 0 }, /*%< expansion (5/6). */
+ { 0x0000, 0 }, /*%< expansion (6/6). */
+};
+
+int ns_msg_getflag(ns_msg handle, int flag) {
+ return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+ const u_char *optr = ptr;
+
+ for ((void)NULL; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0)
+ RETERR(EMSGSIZE);
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+ if (ptr > eom)
+ RETERR(EMSGSIZE);
+ return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
+ const u_char *eom = msg + msglen;
+ int i;
+
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return (-1);
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+ if (msg != eom)
+ RETERR(EMSGSIZE);
+ setsection(handle, ns_s_max);
+ return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ tmp = section;
+ if (tmp < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/*
+ * This is identical to the above but uses network-format (uncompressed) names.
+ */
+int
+ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ if ((tmp = section) < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
+ rr->nname, NS_MAXNNAME, &rr->nnamel);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_msg_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_msg_ptr = msg->_sections[(int)sect];
+ }
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_print.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_print.c
new file mode 100644
index 0000000000..e70df376c1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_print.c
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <isc/dst.h>
+#include <errno.h>
+#include <resolv_joy.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static size_t prune_origin(const char *name, const char *origin);
+static int charstr(const u_char *rdata, const u_char *edata,
+ char **buf, size_t *buflen);
+static int addname(const u_char *msg, size_t msglen,
+ const u_char **p, const char *origin,
+ char **buf, size_t *buflen);
+static void addlen(size_t len, char **buf, size_t *buflen);
+static int addstr(const char *src, size_t len,
+ char **buf, size_t *buflen);
+static int addtab(size_t len, size_t target, int spaced,
+ char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) \
+ do { \
+ if ((x) < 0) \
+ return (-1); \
+ } while (0)
+
+static const char base32hex[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
+
+/* Public. */
+
+/*%
+ * Convert an RR to presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ int n;
+
+ n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
+ ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
+ ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
+ name_ctx, origin, buf, buflen);
+ return (n);
+}
+
+/*%
+ * Convert the fields of an RR into presentation format.
+ *
+ * return:
+ *\li Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrrf(const u_char *msg, size_t msglen,
+ const char *name, ns_class class, ns_type type,
+ u_long ttl, const u_char *rdata, size_t rdlen,
+ const char *name_ctx, const char *origin,
+ char *buf, size_t buflen)
+{
+ const char *obuf = buf;
+ const u_char *edata = rdata + rdlen;
+ int spaced = 0;
+
+ const char *comment;
+ char tmp[100];
+ int len, x;
+
+ /*
+ * Owner.
+ */
+ if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
+ T(addstr("\t\t\t", 3, &buf, &buflen));
+ } else {
+ len = prune_origin(name, origin);
+ if (*name == '\0') {
+ goto root;
+ } else if (len == 0) {
+ T(addstr("@\t\t\t", 4, &buf, &buflen));
+ } else {
+ T(addstr(name, len, &buf, &buflen));
+ /* Origin not used or not root, and no trailing dot? */
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ name[len] == '\0')) && name[len - 1] != '.') {
+ root:
+ T(addstr(".", 1, &buf, &buflen));
+ len++;
+ }
+ T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+ }
+ }
+
+ /*
+ * TTL, Class, Type.
+ */
+ T(x = ns_format_ttl(ttl, buf, buflen));
+ addlen(x, &buf, &buflen);
+ len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+ /*
+ * RData.
+ */
+ switch (type) {
+ case ns_t_a:
+ if (rdlen != (size_t)NS_INADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+
+ case ns_t_hinfo:
+ case ns_t_isdn:
+ /* First word. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+
+ /* Second word, optional in ISDN records. */
+ if (type == ns_t_isdn && rdata == edata)
+ break;
+
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_soa: {
+ u_long t;
+
+ /* Server name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Administrator name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" (\n", 3, &buf, &buflen));
+ spaced = 0;
+
+ if ((edata - rdata) != 5*NS_INT32SZ)
+ goto formerr;
+
+ /* Serial number. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ len = SPRINTF((tmp, "%lu", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; serial\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Refresh interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; refresh\n", 10, &buf, &buflen));
+ spaced = 0;
+
+ /* Retry interval. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; retry\n", 8, &buf, &buflen));
+ spaced = 0;
+
+ /* Expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; expiry\n", 9, &buf, &buflen));
+ spaced = 0;
+
+ /* Minimum TTL. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+ T(len = ns_format_ttl(t, buf, buflen));
+ addlen(len, &buf, &buflen);
+ T(addstr(" )", 2, &buf, &buflen));
+ T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+ T(addstr("; minimum\n", 10, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ case ns_t_kx: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Target. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_px: {
+ u_int t;
+
+ if (rdlen < (size_t)NS_INT16SZ)
+ goto formerr;
+
+ /* Priority. */
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_x25:
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ break;
+
+ case ns_t_txt:
+ case ns_t_spf:
+ while (rdata < edata) {
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ if (rdata < edata)
+ T(addstr(" ", 1, &buf, &buflen));
+ }
+ break;
+
+ case ns_t_nsap: {
+ char t[2+255*3];
+
+ (void) inet_nsap_ntoa(rdlen, rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_aaaa:
+ if (rdlen != (size_t)NS_IN6ADDRSZ)
+ goto formerr;
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+
+ case ns_t_loc: {
+ char t[255];
+
+ /* XXX protocol format checking? */
+ (void) loc_ntoa(rdata, t);
+ T(addstr(t, strlen(t), &buf, &buflen));
+ break;
+ }
+
+ case ns_t_naptr: {
+ u_int order, preference;
+ char t[50];
+
+ if (rdlen < 2U*NS_INT16SZ)
+ goto formerr;
+
+ /* Order, Precedence. */
+ order = ns_get16(rdata); rdata += NS_INT16SZ;
+ preference = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u ", order, preference));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Flags. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Service. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Regexp. */
+ T(len = charstr(rdata, edata, &buf, &buflen));
+ if (len < 0)
+ return (-1);
+ if (len == 0)
+ goto formerr;
+ rdata += len;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_srv: {
+ u_int priority, weight, port;
+ char t[50];
+
+ if (rdlen < 3U*NS_INT16SZ)
+ goto formerr;
+
+ /* Priority, Weight, Port. */
+ priority = ns_get16(rdata); rdata += NS_INT16SZ;
+ weight = ns_get16(rdata); rdata += NS_INT16SZ;
+ port = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((t, "%u %u %u ", priority, weight, port));
+ T(addstr(t, len, &buf, &buflen));
+
+ /* Server. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_minfo:
+ case ns_t_rp:
+ /* Name1. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Name2. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+
+ case ns_t_wks: {
+ int n, lcnt;
+
+ if (rdlen < 1U + NS_INT32SZ)
+ goto formerr;
+
+ /* Address. */
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += NS_INADDRSZ;
+
+ /* Protocol. */
+ len = SPRINTF((tmp, " %u ( ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata += NS_INT8SZ;
+
+ /* Bit map. */
+ n = 0;
+ lcnt = 0;
+ while (rdata < edata) {
+ u_int c = *rdata++;
+ do {
+ if (c & 0200) {
+ if (lcnt == 0) {
+ T(addstr("\n\t\t\t\t", 5,
+ &buf, &buflen));
+ lcnt = 10;
+ spaced = 0;
+ }
+ len = SPRINTF((tmp, "%d ", n));
+ T(addstr(tmp, len, &buf, &buflen));
+ lcnt--;
+ }
+ c <<= 1;
+ } while (++n & 07);
+ }
+ T(addstr(")", 1, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_key:
+ case ns_t_dnskey: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int keyflags, protocol, algorithm, key_id;
+ const char *leader;
+ int n;
+
+ if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+ goto formerr;
+
+ /* Key flags, Protocol, Algorithm. */
+ key_id = dst_s_dns_key_id(rdata, edata-rdata);
+ keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
+ protocol = *rdata++;
+ algorithm = *rdata++;
+ len = SPRINTF((tmp, "0x%04x %u %u",
+ keyflags, protocol, algorithm));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Public key data. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len < 0)
+ goto formerr;
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+ T(addstr(tmp, n, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_sig:
+ case ns_t_rrsig: {
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ u_int type, algorithm, labels, footprint;
+ const char *leader;
+ u_long t;
+ int n;
+
+ if (rdlen < 22U)
+ goto formerr;
+
+ /* Type covered, Algorithm, Label count, Original TTL. */
+ type = ns_get16(rdata); rdata += NS_INT16SZ;
+ algorithm = *rdata++;
+ labels = *rdata++;
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s %d %d %lu ",
+ p_type(type), algorithm, labels, t));
+ T(addstr(tmp, len, &buf, &buflen));
+ if (labels > (u_int)dn_count_labels(name))
+ goto formerr;
+
+ /* Signature expiry. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Time signed. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signature Footprint. */
+ footprint = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", footprint));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Signer's name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Signature. */
+ len = b64_ntop(rdata, edata - rdata,
+ base64_key, sizeof base64_key);
+ if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ } else
+ leader = " ";
+ if (len < 0)
+ goto formerr;
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_nxt: {
+ int n, c;
+
+ /* Next domain name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ /* Type bit map. */
+ n = edata - rdata;
+ for (c = 0; c < n*8; c++)
+ if (NS_NXT_BIT_ISSET(c, rdata)) {
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_cert: {
+ u_int c_type, key_tag, alg;
+ int n;
+ unsigned int siz;
+ char base64_cert[8192], tmp[40];
+ const char *leader;
+
+ c_type = ns_get16(rdata); rdata += NS_INT16SZ;
+ key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+ alg = (u_int) *rdata++;
+
+ len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+ T(addstr(tmp, len, &buf, &buflen));
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_cert) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ }
+ else {
+ len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+ if (len < 0)
+ goto formerr;
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_cert + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_tkey: {
+ /* KJD - need to complete this */
+ u_long t;
+ int mode, err, keysize;
+
+ /* Algorithm name. */
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+
+ /* Inception. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Experation. */
+ t = ns_get32(rdata); rdata += NS_INT32SZ;
+ len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* Mode , Error, Key Size. */
+ /* Priority, Weight, Port. */
+ mode = ns_get16(rdata); rdata += NS_INT16SZ;
+ err = ns_get16(rdata); rdata += NS_INT16SZ;
+ keysize = ns_get16(rdata); rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ /* XXX need to dump key, print otherdata length & other data */
+ break;
+ }
+
+ case ns_t_tsig: {
+ /* BEW - need to complete this */
+ int n;
+
+ T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ T(addstr(" ", 1, &buf, &buflen));
+ rdata += 8; /*%< time */
+ n = ns_get16(rdata); rdata += INT16SZ;
+ rdata += n; /*%< sig */
+ n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
+ sprintf(buf, "%d", ns_get16(rdata));
+ rdata += INT16SZ;
+ addlen(strlen(buf), &buf, &buflen);
+ break;
+ }
+
+ case ns_t_a6: {
+ struct in6_addr a;
+ int pbyte, pbit;
+
+ /* prefix length */
+ if (rdlen == 0U) goto formerr;
+ len = SPRINTF((tmp, "%d ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ pbit = *rdata;
+ if (pbit > 128) goto formerr;
+ pbyte = (pbit & ~7) / 8;
+ rdata++;
+
+ /* address suffix: provided only when prefix len != 128 */
+ if (pbit < 128) {
+ if (rdata + pbyte >= edata) goto formerr;
+ memset(&a, 0, sizeof(a));
+ memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+ (void) inet_ntop(AF_INET6, &a, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += sizeof(a) - pbyte;
+ }
+
+ /* prefix name: provided only when prefix len > 0 */
+ if (pbit == 0)
+ break;
+ if (rdata >= edata) goto formerr;
+ T(addstr(" ", 1, &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ break;
+ }
+
+ case ns_t_opt: {
+ len = SPRINTF((tmp, "%u bytes", class));
+ T(addstr(tmp, len, &buf, &buflen));
+ break;
+ }
+
+ case ns_t_ds:
+ case ns_t_dlv:
+ case ns_t_sshfp: {
+ u_int t;
+
+ if (type == ns_t_ds || type == ns_t_dlv) {
+ if (rdlen < 4U) goto formerr;
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ } else
+ if (rdlen < 2U) goto formerr;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ while (rdata < edata) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ break;
+ }
+
+ case ns_t_nsec3:
+ case ns_t_nsec3param: {
+ u_int t, w, l, j, k, c;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ t = *rdata++;
+ if (t == 0) {
+ T(addstr("-", 1, &buf, &buflen));
+ } else {
+ while (t-- > 0) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ }
+ if (type == ns_t_nsec3param)
+ break;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ t = *rdata++;
+ while (t > 0) {
+ switch (t) {
+ case 1:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
+ tmp[2] = tmp[3] = tmp[4] = '=';
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 2:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
+ tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 3:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 4:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[(rdata[3]<<3)&0x18];
+ tmp[7] = '=';
+ break;
+ default:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
+ ((rdata[4]>>5)&0x07)];
+ tmp[7] = base32hex[(rdata[4]&0x1f)];
+ break;
+ }
+ T(addstr(tmp, 8, &buf, &buflen));
+ if (t >= 5) {
+ rdata += 5;
+ t -= 5;
+ } else {
+ rdata += t;
+ t -= t;
+ }
+ }
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_nsec: {
+ u_int w, l, j, k, c;
+
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_dhcid: {
+ int n;
+ unsigned int siz;
+ char base64_dhcid[8192];
+ const char *leader;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_dhcid) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_dhcid + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ }
+
+ case ns_t_ipseckey: {
+ int n;
+ unsigned int siz;
+ char base64_key[8192];
+ const char *leader;
+
+ if (rdlen < 2)
+ goto formerr;
+
+ switch (rdata[1]) {
+ case 0:
+ case 3:
+ if (rdlen < 3)
+ goto formerr;
+ break;
+ case 1:
+ if (rdlen < 7)
+ goto formerr;
+ break;
+ case 2:
+ if (rdlen < 19)
+ goto formerr;
+ break;
+ default:
+ comment = "unknown IPSECKEY gateway type";
+ goto hexify;
+ }
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ switch (rdata[-2]) {
+ case 0:
+ T(addstr(".", 1, &buf, &buflen));
+ break;
+ case 1:
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 4;
+ break;
+ case 2:
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 16;
+ break;
+ case 3:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ if (rdata >= edata)
+ break;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_key, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ }
+
+ case ns_t_hip: {
+ unsigned int i, hip_len, algorithm, key_len;
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ unsigned int siz;
+ const char *leader = "\n\t\t\t\t\t";
+
+ hip_len = *rdata++;
+ algorithm = *rdata++;
+ key_len = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+
+ siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = sprintf(tmp, "( %u ", algorithm);
+ T(addstr(tmp, len, &buf, &buflen));
+
+ for (i = 0; i < hip_len; i++) {
+ len = sprintf(tmp, "%02X", *rdata);
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+
+ len = b64_ntop(rdata, key_len, base64_key, siz);
+ if (len < 0)
+ goto formerr;
+
+ T(addstr(base64_key, len, &buf, &buflen));
+
+ rdata += key_len;
+ while (rdata < edata) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin,
+ &buf, &buflen));
+ }
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ default:
+ comment = "unknown RR type";
+ goto hexify;
+ }
+ return (buf - obuf);
+ formerr:
+ comment = "RR format error";
+ hexify: {
+ int n, m;
+ char *p;
+
+ len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
+ rdlen != 0U ? " (" : "", comment));
+ T(addstr(tmp, len, &buf, &buflen));
+ while (rdata < edata) {
+ p = tmp;
+ p += SPRINTF((p, "\n\t"));
+ spaced = 0;
+ n = MIN(16, edata - rdata);
+ for (m = 0; m < n; m++)
+ p += SPRINTF((p, "%02x ", rdata[m]));
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ if (n < 16) {
+ T(addstr(")", 1, &buf, &buflen));
+ T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
+ }
+ p = tmp;
+ p += SPRINTF((p, "; "));
+ for (m = 0; m < n; m++)
+ *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
+ ? rdata[m]
+ : '.';
+ T(addstr(tmp, p - tmp, &buf, &buflen));
+ rdata += n;
+ }
+ return (buf - obuf);
+ }
+}
+
+/* Private. */
+
+/*%
+ * size_t
+ * prune_origin(name, origin)
+ * Find out if the name is at or under the current origin.
+ * return:
+ * Number of characters in name before start of origin,
+ * or length of name if origin does not match.
+ * notes:
+ * This function should share code with samedomain().
+ */
+static size_t
+prune_origin(const char *name, const char *origin) {
+ const char *oname = name;
+
+ while (*name != '\0') {
+ if (origin != NULL && ns_samename(name, origin) == 1)
+ return (name - oname - (name > oname));
+ while (*name != '\0') {
+ if (*name == '\\') {
+ name++;
+ /* XXX need to handle \nnn form. */
+ if (*name == '\0')
+ break;
+ } else if (*name == '.') {
+ name++;
+ break;
+ }
+ name++;
+ }
+ }
+ return (name - oname);
+}
+
+/*%
+ * int
+ * charstr(rdata, edata, buf, buflen)
+ * Format a <character-string> into the presentation buffer.
+ * return:
+ * Number of rdata octets consumed
+ * 0 for protocol format error
+ * -1 for output buffer error
+ * side effects:
+ * buffer is advanced on success.
+ */
+static int
+charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
+ const u_char *odata = rdata;
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ if (rdata < edata) {
+ int n = *rdata;
+
+ if (rdata + 1 + n <= edata) {
+ rdata++;
+ while (n-- > 0) {
+ if (strchr("\n\"\\", *rdata) != NULL)
+ if (addstr("\\", 1, buf, buflen) < 0)
+ goto enospc;
+ if (addstr((const char *)rdata, 1,
+ buf, buflen) < 0)
+ goto enospc;
+ rdata++;
+ }
+ }
+ }
+ if (addstr("\"", 1, buf, buflen) < 0)
+ goto enospc;
+ return (rdata - odata);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static int
+addname(const u_char *msg, size_t msglen,
+ const u_char **pp, const char *origin,
+ char **buf, size_t *buflen)
+{
+ size_t newlen, save_buflen = *buflen;
+ char *save_buf = *buf;
+ int n;
+
+ n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
+ if (n < 0)
+ goto enospc; /*%< Guess. */
+ newlen = prune_origin(*buf, origin);
+ if (**buf == '\0') {
+ goto root;
+ } else if (newlen == 0U) {
+ /* Use "@" instead of name. */
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for "@\0". */
+ (*buf)[newlen++] = '@';
+ (*buf)[newlen] = '\0';
+ } else {
+ if (((origin == NULL || origin[0] == '\0') ||
+ (origin[0] != '.' && origin[1] != '\0' &&
+ (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
+ /* No trailing dot. */
+ root:
+ if (newlen + 2 > *buflen)
+ goto enospc; /* No room for ".\0". */
+ (*buf)[newlen++] = '.';
+ (*buf)[newlen] = '\0';
+ }
+ }
+ *pp += n;
+ addlen(newlen, buf, buflen);
+ **buf = '\0';
+ return (newlen);
+ enospc:
+ errno = ENOSPC;
+ *buf = save_buf;
+ *buflen = save_buflen;
+ return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+ INSIST(len <= *buflen);
+ *buf += len;
+ *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+ if (len >= *buflen) {
+ errno = ENOSPC;
+ return (-1);
+ }
+ memcpy(*buf, src, len);
+ addlen(len, buf, buflen);
+ **buf = '\0';
+ return (0);
+}
+
+static int
+addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
+ size_t save_buflen = *buflen;
+ char *save_buf = *buf;
+ int t;
+
+ if (spaced || len >= target - 1) {
+ T(addstr(" ", 2, buf, buflen));
+ spaced = 1;
+ } else {
+ for (t = (target - len - 1) / 8; t >= 0; t--)
+ if (addstr("\t", 1, buf, buflen) < 0) {
+ *buflen = save_buflen;
+ *buf = save_buf;
+ return (-1);
+ }
+ spaced = 0;
+ }
+ return (spaced);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_rdata.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_rdata.c
new file mode 100644
index 0000000000..eac4052278
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_rdata.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_rdata.c,v 1.2 2009/01/23 23:49:15 tbox Exp $";
+#endif
+
+#include "port_before.h"
+
+#if __OpenBSD__
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv_joy.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#define CONSUME_SRC \
+ do { \
+ rdata += n, rdlen -= n; \
+ } while (0)
+
+#define CONSUME_DST \
+ do { \
+ nrdata += n, nrdsiz -= n, nrdlen += n; \
+ } while (0)
+
+#define UNPACK_DNAME \
+ do { \
+ size_t t; \
+ \
+ if ((n = ns_name_unpack2(msg,eom,rdata,nrdata,nrdsiz,&t))<0) {\
+ errno = EMSGSIZE; \
+ return (-1); \
+ } \
+ CONSUME_SRC; \
+ n = t; \
+ CONSUME_DST; \
+ } while (0)
+
+#define UNPACK_SOME(x) \
+ do { \
+ n = (x); \
+ if ((size_t)n > rdlen || (size_t)n > nrdsiz) { \
+ errno = EMSGSIZE; \
+ return (-1); \
+ } \
+ memcpy(nrdata, rdata, n); \
+ CONSUME_SRC; CONSUME_DST; \
+ } while (0)
+
+#define UNPACK_REST(x) \
+ do { \
+ n = (x); \
+ if ((size_t)n != rdlen) { \
+ errno = EMSGSIZE; \
+ return (-1); \
+ } \
+ memcpy(nrdata, rdata, n); \
+ CONSUME_SRC; CONSUME_DST; \
+ } while (0)
+
+ssize_t
+ns_rdata_unpack(const u_char *msg, const u_char *eom,
+ ns_type type, const u_char *rdata, size_t rdlen,
+ u_char *nrdata, size_t nrdsiz)
+{
+ size_t nrdlen = 0;
+ int n;
+
+ switch (type) {
+ case ns_t_a:
+ UNPACK_REST(NS_INADDRSZ);
+ break;
+ case ns_t_aaaa:
+ UNPACK_REST(NS_IN6ADDRSZ);
+ break;
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ UNPACK_DNAME;
+ break;
+ case ns_t_soa:
+ UNPACK_DNAME;
+ UNPACK_DNAME;
+ UNPACK_SOME(NS_INT32SZ * 5);
+ break;
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ UNPACK_SOME(NS_INT16SZ);
+ UNPACK_DNAME;
+ break;
+ case ns_t_px:
+ UNPACK_SOME(NS_INT16SZ);
+ UNPACK_DNAME;
+ UNPACK_DNAME;
+ break;
+ case ns_t_srv:
+ UNPACK_SOME(NS_INT16SZ * 3);
+ UNPACK_DNAME;
+ break;
+ case ns_t_minfo:
+ case ns_t_rp:
+ UNPACK_DNAME;
+ UNPACK_DNAME;
+ break;
+ default:
+ UNPACK_SOME(rdlen);
+ break;
+ }
+ if (rdlen > 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (nrdlen);
+}
+
+#define EQUAL_CONSUME \
+ do { \
+ rdata1 += n, rdlen1 -= n; \
+ rdata2 += n, rdlen2 -= n; \
+ } while (0)
+
+#define EQUAL_DNAME \
+ do { \
+ ssize_t n; \
+ \
+ if (rdlen1 != rdlen2) \
+ return (0); \
+ n = ns_name_eq(rdata1, rdlen1, rdata2, rdlen2); \
+ if (n <= 0) \
+ return (n); \
+ n = rdlen1; \
+ EQUAL_CONSUME; \
+ } while (0)
+
+#define EQUAL_SOME(x) \
+ do { \
+ size_t n = (x); \
+ \
+ if (n > rdlen1 || n > rdlen2) { \
+ errno = EMSGSIZE; \
+ return (-1); \
+ } \
+ if (memcmp(rdata1, rdata2, n) != 0) \
+ return (0); \
+ EQUAL_CONSUME; \
+ } while (0)
+
+int
+ns_rdata_equal(ns_type type,
+ const u_char *rdata1, size_t rdlen1,
+ const u_char *rdata2, size_t rdlen2)
+{
+ switch (type) {
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ EQUAL_DNAME;
+ break;
+ case ns_t_soa:
+ /* "There can be only one." --Highlander */
+ break;
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ EQUAL_SOME(NS_INT16SZ);
+ EQUAL_DNAME;
+ break;
+ case ns_t_px:
+ EQUAL_SOME(NS_INT16SZ);
+ EQUAL_DNAME;
+ EQUAL_DNAME;
+ break;
+ case ns_t_srv:
+ EQUAL_SOME(NS_INT16SZ * 3);
+ EQUAL_DNAME;
+ break;
+ case ns_t_minfo:
+ case ns_t_rp:
+ EQUAL_DNAME;
+ EQUAL_DNAME;
+ break;
+ default:
+ EQUAL_SOME(rdlen1);
+ break;
+ }
+ if (rdlen1 != 0 || rdlen2 != 0)
+ return (0);
+ return (1);
+}
+
+#define REFERS_DNAME \
+ do { \
+ int n; \
+ \
+ n = ns_name_eq(rdata, rdlen, nname, NS_MAXNNAME); \
+ if (n < 0) \
+ return (-1); \
+ if (n > 0) \
+ return (1); \
+ n = dn_skipname(rdata, rdata + rdlen); \
+ if (n < 0) \
+ return (-1); \
+ CONSUME_SRC; \
+ } while (0)
+
+#define REFERS_SOME(x) \
+ do { \
+ size_t n = (x); \
+ \
+ if (n > rdlen) { \
+ errno = EMSGSIZE; \
+ return (-1); \
+ } \
+ CONSUME_SRC; \
+ } while (0)
+
+int
+ns_rdata_refers(ns_type type,
+ const u_char *rdata, size_t rdlen,
+ const u_char *nname)
+{
+ switch (type) {
+ case ns_t_cname:
+ case ns_t_mb:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_dname:
+ REFERS_DNAME;
+ break;
+ case ns_t_soa:
+ REFERS_DNAME;
+ REFERS_DNAME;
+ REFERS_SOME(NS_INT32SZ * 5);
+ break;
+ case ns_t_mx:
+ case ns_t_afsdb:
+ case ns_t_rt:
+ REFERS_SOME(NS_INT16SZ);
+ REFERS_DNAME;
+ break;
+ case ns_t_px:
+ REFERS_SOME(NS_INT16SZ);
+ REFERS_DNAME;
+ REFERS_DNAME;
+ break;
+ case ns_t_srv:
+ REFERS_SOME(NS_INT16SZ * 3);
+ REFERS_DNAME;
+ break;
+ case ns_t_minfo:
+ case ns_t_rp:
+ REFERS_DNAME;
+ REFERS_DNAME;
+ break;
+ default:
+ REFERS_SOME(rdlen);
+ break;
+ }
+ if (rdlen != 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_samedomain.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_samedomain.c
new file mode 100644
index 0000000000..5e9f5cab54
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_samedomain.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*%
+ * Check whether a name belongs to a domain.
+ *
+ * Inputs:
+ *\li a - the domain whose ancestory is being verified
+ *\li b - the potential ancestor we're checking against
+ *
+ * Return:
+ *\li boolean - is a at or below b?
+ *
+ * Notes:
+ *\li Trailing dots are first removed from name and domain.
+ * Always compare complete subdomains, not only whether the
+ * domain name is the trailing string of the given name.
+ *
+ *\li "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ * but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+ size_t la, lb;
+ int diff, i, escaped;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+ if (la != 0U && a[la - 1] == '.') {
+ escaped = 0;
+ /* Note this loop doesn't get executed if la==1. */
+ for (i = la - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ la--;
+ }
+
+ /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+ if (lb != 0U && b[lb - 1] == '.') {
+ escaped = 0;
+ /* note this loop doesn't get executed if lb==1 */
+ for (i = lb - 2; i >= 0; i--)
+ if (b[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (!escaped)
+ lb--;
+ }
+
+ /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+ if (lb == 0U)
+ return (1);
+
+ /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+ if (lb > la)
+ return (0);
+
+ /* 'a' and 'b' being equal at this point indicates sameness. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ diff = la - lb;
+
+ /*
+ * If 'a' is only 1 character longer than 'b', then it can't be
+ * a subdomain of 'b' (because of the need for the '.' label
+ * separator).
+ */
+ if (diff < 2)
+ return (0);
+
+ /*
+ * If the character before the last 'lb' characters of 'b'
+ * isn't '.', then it can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com").
+ */
+ if (a[diff - 1] != '.')
+ return (0);
+
+ /*
+ * We're not sure about that '.', however. It could be escaped
+ * and thus not a really a label separator.
+ */
+ escaped = 0;
+ for (i = diff - 2; i >= 0; i--)
+ if (a[i] == '\\') {
+ if (escaped)
+ escaped = 0;
+ else
+ escaped = 1;
+ } else
+ break;
+ if (escaped)
+ return (0);
+
+ /* Now compare aligned trailing substring. */
+ cp = a + diff;
+ return (strncasecmp(cp, b, lb) == 0);
+}
+
+/*%
+ * is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+ return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+
+/*%
+ * make a canonical copy of domain name "src"
+ *
+ * notes:
+ * \code
+ * foo -> foo.
+ * foo. -> foo.
+ * foo.. -> foo.
+ * foo\. -> foo\..
+ * foo\\. -> foo\\.
+ * \endcode
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+ size_t n = strlen(src);
+
+ if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ strcpy(dst, src);
+ while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */
+ if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */
+ (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */
+ break;
+ else
+ dst[--n] = '\0';
+ dst[n++] = '.';
+ dst[n] = '\0';
+ return (0);
+}
+
+/*%
+ * determine whether domain name "a" is the same as domain name "b"
+ *
+ * return:
+ *\li -1 on error
+ *\li 0 if names differ
+ *\li 1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+ char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+ if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+ ns_makecanon(b, tb, sizeof tb) < 0)
+ return (-1);
+ if (strcasecmp(ta, tb) == 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_sign.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_sign.c
new file mode 100644
index 0000000000..fc7dd19f7b
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_sign.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_sign.c,v 1.6 2006/03/09 23:57:56 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eob) { \
+ errno = EMSGSIZE; \
+ return(NS_TSIG_ERROR_NO_SPACE); \
+ } \
+ } while (0)
+
+/*%
+ * ns_sign
+ *
+ * Parameters:
+ *\li msg message to be sent
+ *\li msglen input - length of message
+ * output - length of signed message
+ *\li msgsize length of buffer containing message
+ *\li error value to put in the error field
+ *\li key tsig key used for signing
+ *\li querysig (response), the signature in the query
+ *\li querysiglen (response), the length of the signature in the query
+ *\li sig a buffer to hold the generated signature
+ *\li siglen input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ *\li - bad input data (-1)
+ *\li - bad key / sign failed (-BADKEY)
+ *\li - not enough space (NS_TSIG_ERROR_NO_SPACE)
+ */
+int
+ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned)
+{
+ return(ns_sign2(msg, msglen, msgsize, error, k,
+ querysig, querysiglen, sig, siglen,
+ in_timesigned, NULL, NULL));
+}
+
+int
+ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp, *eob;
+ u_char *lenp;
+ u_char *alg;
+ int n;
+ time_t timesigned;
+ u_char name[NS_MAXCDNAME];
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
+ return (-1);
+
+ cp = msg + *msglen;
+ eob = msg + msgsize;
+
+ /* Name. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ n = ns_name_pton(key->dk_key_name, name, sizeof name);
+ if (n != -1)
+ n = ns_name_pack(name, cp, eob - cp,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr);
+
+ } else {
+ n = ns_name_pton("", name, sizeof name);
+ if (n != -1)
+ n = ns_name_pack(name, cp, eob - cp, NULL, NULL);
+ }
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(ns_t_tsig, cp);
+ PUTSHORT(ns_c_any, cp);
+ PUTLONG(0, cp); /*%< TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ }
+ else
+ n = dn_comp("", cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ alg = cp;
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(0, cp);
+ timesigned = time(NULL);
+ if (error != ns_r_badtime)
+ PUTLONG(timesigned, cp);
+ else
+ PUTLONG(in_timesigned, cp);
+ PUTSHORT(NS_TSIG_FUDGE, cp);
+
+ /* Compute the signature. */
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[NS_MAXCDNAME], *cp2;
+ int n;
+
+ dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+
+ /* Digest the query signature, if this is a response. */
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_ntol(name, buf, sizeof(buf));
+ INSIST(n > 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ cp2 = buf;
+ PUTSHORT(ns_c_any, cp2);
+ PUTLONG(0, cp2);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_ntol(alg, buf, sizeof(buf));
+ INSIST(n > 0);
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed, fudge, error, and other data */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ if (error != ns_r_badtime)
+ PUTLONG(timesigned, cp2);
+ else
+ PUTLONG(in_timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+ PUTSHORT(error, cp2); /*%< Error */
+ if (error != ns_r_badtime)
+ PUTSHORT(0, cp2); /*%< Other data length */
+ else {
+ PUTSHORT(INT16SZ+INT32SZ, cp2); /*%< Other data length */
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp2);
+ }
+ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
+ NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sig, *siglen);
+ if (n < 0)
+ return (-ns_r_badkey);
+ *siglen = n;
+ } else
+ *siglen = 0;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, INT16SZ + (*siglen));
+ PUTSHORT(*siglen, cp);
+ memcpy(cp, sig, *siglen);
+ cp += (*siglen);
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+ PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */
+ PUTSHORT(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ if (error != ns_r_badtime)
+ PUTSHORT(0, cp); /*%< Other data length */
+ else {
+ PUTSHORT(INT16SZ+INT32SZ, cp); /*%< Other data length */
+ BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
+ PUTSHORT(0, cp); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp);
+ }
+
+ /* Go back and fill in the length. */
+ PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
+
+int
+ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done)
+{
+ return (ns_sign_tcp2(msg, msglen, msgsize, error, state,
+ done, NULL, NULL));
+}
+
+int
+ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error,
+ ns_tcp_tsig_state *state, int done,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ u_char *cp, *eob, *lenp;
+ u_char buf[MAXDNAME], *cp2;
+ HEADER *hp = (HEADER *)msg;
+ time_t timesigned;
+ int n;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_sign2(msg, msglen, msgsize, error, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, 0,
+ dnptrs, lastdnptr));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+ dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, INT16SZ, NULL, 0);
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
+ NULL, 0);
+
+ if (done == 0 && (state->counter % 100 != 0))
+ return (0);
+
+ cp = msg + *msglen;
+ eob = msg + msgsize;
+
+ /* Name. */
+ n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Type, class, ttl, length (not filled in yet). */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(ns_t_tsig, cp);
+ PUTSHORT(ns_c_any, cp);
+ PUTLONG(0, cp); /*%< TTL */
+ lenp = cp;
+ cp += 2;
+
+ /* Alg. */
+ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+ if (n < 0)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ cp += n;
+
+ /* Time. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ PUTSHORT(0, cp);
+ timesigned = time(NULL);
+ PUTLONG(timesigned, cp);
+ PUTSHORT(NS_TSIG_FUDGE, cp);
+
+ /*
+ * Compute the signature.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time */
+ PUTLONG(timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+ dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ state->sig, sizeof(state->sig));
+ if (n < 0)
+ return (-ns_r_badkey);
+ state->siglen = n;
+
+ /* Add the signature. */
+ BOUNDS_CHECK(cp, INT16SZ + state->siglen);
+ PUTSHORT(state->siglen, cp);
+ memcpy(cp, state->sig, state->siglen);
+ cp += state->siglen;
+
+ /* The original message ID & error. */
+ BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+ PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */
+ PUTSHORT(error, cp);
+
+ /* Other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ PUTSHORT(0, cp);
+
+ /* Go back and fill in the length. */
+ PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+ *msglen = (cp - msg);
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_ttl.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_ttl.c
new file mode 100644
index 0000000000..69c2f83f57
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_ttl.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else (void)NULL
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+ char *odst = dst;
+ int secs, mins, hours, days, weeks, x;
+ char *p;
+
+ secs = src % 60; src /= 60;
+ mins = src % 60; src /= 60;
+ hours = src % 24; src /= 24;
+ days = src % 7; src /= 7;
+ weeks = src; src = 0;
+
+ x = 0;
+ if (weeks) {
+ T(fmt1(weeks, 'W', &dst, &dstlen));
+ x++;
+ }
+ if (days) {
+ T(fmt1(days, 'D', &dst, &dstlen));
+ x++;
+ }
+ if (hours) {
+ T(fmt1(hours, 'H', &dst, &dstlen));
+ x++;
+ }
+ if (mins) {
+ T(fmt1(mins, 'M', &dst, &dstlen));
+ x++;
+ }
+ if (secs || !(weeks || days || hours || mins)) {
+ T(fmt1(secs, 'S', &dst, &dstlen));
+ x++;
+ }
+
+ if (x > 1) {
+ int ch;
+
+ for (p = odst; (ch = *p) != '\0'; p++)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+ }
+
+ return (dst - odst);
+}
+
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+ u_long ttl, tmp;
+ int ch, digits, dirty;
+
+ ttl = 0;
+ tmp = 0;
+ digits = 0;
+ dirty = 0;
+ while ((ch = *src++) != '\0') {
+ if (!isascii(ch) || !isprint(ch))
+ goto einval;
+ if (isdigit(ch)) {
+ tmp *= 10;
+ tmp += (ch - '0');
+ digits++;
+ continue;
+ }
+ if (digits == 0)
+ goto einval;
+ if (islower(ch))
+ ch = toupper(ch);
+ switch (ch) {
+ case 'W': tmp *= 7;
+ case 'D': tmp *= 24;
+ case 'H': tmp *= 60;
+ case 'M': tmp *= 60;
+ case 'S': break;
+ default: goto einval;
+ }
+ ttl += tmp;
+ tmp = 0;
+ digits = 0;
+ dirty = 1;
+ }
+ if (digits > 0) {
+ if (dirty)
+ goto einval;
+ else
+ ttl += tmp;
+ } else if (!dirty)
+ goto einval;
+ *dst = ttl;
+ return (0);
+
+ einval:
+ errno = EINVAL;
+ return (-1);
+}
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+ char tmp[50];
+ size_t len;
+
+ len = SPRINTF((tmp, "%d%c", t, s));
+ if (len + 1 > *buflen)
+ return (-1);
+ strcpy(*buf, tmp);
+ *buf += len;
+ *buflen -= len;
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/nameser/ns_verify.c b/usr/src/lib/libresolv2_joy/common/nameser/ns_verify.c
new file mode 100644
index 0000000000..b4b63d4641
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/nameser/ns_verify.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_verify.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+/* Private. */
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ return (NS_TSIG_ERROR_FORMERR); \
+ } \
+ } while (0)
+
+/* Public. */
+
+u_char *
+ns_find_tsig(u_char *msg, u_char *eom) {
+ HEADER *hp = (HEADER *)msg;
+ int n, type;
+ u_char *cp = msg, *start;
+
+ if (msg == NULL || eom == NULL || msg > eom)
+ return (NULL);
+
+ if (cp + HFIXEDSZ >= eom)
+ return (NULL);
+
+ if (hp->arcount == 0)
+ return (NULL);
+
+ cp += HFIXEDSZ;
+
+ n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+
+ start = cp;
+ n = dn_skipname(cp, eom);
+ if (n < 0)
+ return (NULL);
+ cp += n;
+ if (cp + INT16SZ >= eom)
+ return (NULL);
+
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NULL);
+ return (start);
+}
+
+/* ns_verify
+ *
+ * Parameters:
+ *\li statp res stuff
+ *\li msg received message
+ *\li msglen length of message
+ *\li key tsig key used for verifying.
+ *\li querysig (response), the signature in the query
+ *\li querysiglen (response), the length of the signature in the query
+ *\li sig (query), a buffer to hold the signature
+ *\li siglen (query), input - length of signature buffer
+ * output - length of signature
+ *
+ * Errors:
+ *\li - bad input (-1)
+ *\li - invalid dns message (NS_TSIG_ERROR_FORMERR)
+ *\li - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
+ *\li - key doesn't match (-ns_r_badkey)
+ *\li - TSIG verification fails with BADKEY (-ns_r_badkey)
+ *\li - TSIG verification fails with BADSIG (-ns_r_badsig)
+ *\li - TSIG verification fails with BADTIME (-ns_r_badtime)
+ *\li - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
+ *\li - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
+ *\li - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
+ */
+int
+ns_verify(u_char *msg, int *msglen, void *k,
+ const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
+ time_t *timesigned, int nostrip)
+{
+ HEADER *hp = (HEADER *)msg;
+ DST_KEY *key = (DST_KEY *)k;
+ u_char *cp = msg, *eom;
+ char name[MAXDNAME], alg[MAXDNAME];
+ u_char *recstart, *rdatastart;
+ u_char *sigstart, *otherstart;
+ int n;
+ int error;
+ u_int16_t type, length;
+ u_int16_t fudge, sigfieldlen, otherfieldlen;
+
+ dst_init();
+ if (msg == NULL || msglen == NULL || *msglen < 0)
+ return (-1);
+
+ eom = msg + *msglen;
+
+ recstart = ns_find_tsig(msg, eom);
+ if (recstart == NULL)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ cp = recstart;
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += INT16SZ + INT32SZ;
+ GETSHORT(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ rdatastart = cp;
+ n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ cp += INT16SZ;
+ GETLONG((*timesigned), cp);
+ GETSHORT(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Skip id and read error. */
+ BOUNDS_CHECK(cp, 2*INT16SZ);
+ cp += INT16SZ;
+ GETSHORT(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ otherstart = cp;
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Verify that the key used is OK. */
+ if (key != NULL) {
+ if (key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (error != ns_r_badsig && error != ns_r_badkey) {
+ if (ns_samename(key->dk_key_name, name) != 1)
+ return (-ns_r_badkey);
+ }
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+
+ /*
+ * Do the verification.
+ */
+
+ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+ void *ctx;
+ u_char buf[MAXDNAME];
+ u_char buf2[MAXDNAME];
+
+ /* Digest the query signature, if this is a response. */
+ dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+ if (querysiglen > 0 && querysig != NULL) {
+ u_int16_t len_n = htons(querysiglen);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ (u_char *)&len_n, INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ querysig, querysiglen, NULL, 0);
+ }
+
+ /* Digest the message. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
+ NULL, 0);
+
+ /* Digest the key name. */
+ n = ns_name_pton(name, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the class and TTL. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ recstart + dn_skipname(recstart, eom) + INT16SZ,
+ INT16SZ + INT32SZ, NULL, 0);
+
+ /* Digest the algorithm. */
+ n = ns_name_pton(alg, buf2, sizeof(buf2));
+ if (n < 0)
+ return (-1);
+ n = ns_name_ntol(buf2, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+ /* Digest the time signed and fudge. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ rdatastart + dn_skipname(rdatastart, eom),
+ INT16SZ + INT32SZ + INT16SZ, NULL, 0);
+
+ /* Digest the error and other data. */
+ dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+ otherstart - INT16SZ - INT16SZ,
+ otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+ sigstart, sigfieldlen);
+
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sig != NULL && siglen != NULL) {
+ if (*siglen < sigfieldlen)
+ return (NS_TSIG_ERROR_NO_SPACE);
+ memcpy(sig, sigstart, sigfieldlen);
+ *siglen = sigfieldlen;
+ }
+ } else {
+ if (sigfieldlen > 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (sig != NULL && siglen != NULL)
+ *siglen = 0;
+ }
+
+ /* Reset the counter, since we still need to check for badtime. */
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ /* Verify the time. */
+ if (abs((*timesigned) - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ if (nostrip == 0) {
+ *msglen = recstart - msg;
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ }
+
+ if (error != NOERROR)
+ return (error);
+
+ return (0);
+}
+
+int
+ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
+ ns_tcp_tsig_state *state)
+{
+ dst_init();
+ if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+ return (-1);
+ state->counter = -1;
+ state->key = k;
+ if (state->key->dk_alg != KEY_HMAC_MD5)
+ return (-ns_r_badkey);
+ if (querysiglen > (int)sizeof(state->sig))
+ return (-1);
+ memcpy(state->sig, querysig, querysiglen);
+ state->siglen = querysiglen;
+ return (0);
+}
+
+int
+ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
+ int required)
+{
+ HEADER *hp = (HEADER *)msg;
+ u_char *recstart, *sigstart;
+ unsigned int sigfieldlen, otherfieldlen;
+ u_char *cp, *eom, *cp2;
+ char name[MAXDNAME], alg[MAXDNAME];
+ u_char buf[MAXDNAME];
+ int n, type, length, fudge, error;
+ time_t timesigned;
+
+ if (msg == NULL || msglen == NULL || state == NULL)
+ return (-1);
+
+ eom = msg + *msglen;
+
+ state->counter++;
+ if (state->counter == 0)
+ return (ns_verify(msg, msglen, state->key,
+ state->sig, state->siglen,
+ state->sig, &state->siglen, &timesigned, 0));
+
+ if (state->siglen > 0) {
+ u_int16_t siglen_n = htons(state->siglen);
+
+ dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
+ NULL, 0, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ (u_char *)&siglen_n, INT16SZ, NULL, 0);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ state->sig, state->siglen, NULL, 0);
+ state->siglen = 0;
+ }
+
+ cp = recstart = ns_find_tsig(msg, eom);
+
+ if (recstart == NULL) {
+ if (required)
+ return (NS_TSIG_ERROR_NO_TSIG);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, *msglen, NULL, 0);
+ return (0);
+ }
+
+ hp->arcount = htons(ntohs(hp->arcount) - 1);
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ msg, recstart - msg, NULL, 0);
+
+ /* Read the key name. */
+ n = dn_expand(msg, eom, cp, name, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ cp += n;
+
+ /* Read the type. */
+ BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+ GETSHORT(type, cp);
+ if (type != ns_t_tsig)
+ return (NS_TSIG_ERROR_NO_TSIG);
+
+ /* Skip the class and TTL, save the length. */
+ cp += INT16SZ + INT32SZ;
+ GETSHORT(length, cp);
+ if (eom - cp != length)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /* Read the algorithm name. */
+ n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+ if (n < 0)
+ return (NS_TSIG_ERROR_FORMERR);
+ if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ return (-ns_r_badkey);
+ cp += n;
+
+ /* Verify that the key used is OK. */
+ if ((ns_samename(state->key->dk_key_name, name) != 1 ||
+ state->key->dk_alg != KEY_HMAC_MD5))
+ return (-ns_r_badkey);
+
+ /* Read the time signed and fudge. */
+ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+ cp += INT16SZ;
+ GETLONG(timesigned, cp);
+ GETSHORT(fudge, cp);
+
+ /* Read the signature. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(sigfieldlen, cp);
+ BOUNDS_CHECK(cp, sigfieldlen);
+ sigstart = cp;
+ cp += sigfieldlen;
+
+ /* Skip id and read error. */
+ BOUNDS_CHECK(cp, 2*INT16SZ);
+ cp += INT16SZ;
+ GETSHORT(error, cp);
+
+ /* Parse the other data. */
+ BOUNDS_CHECK(cp, INT16SZ);
+ GETSHORT(otherfieldlen, cp);
+ BOUNDS_CHECK(cp, otherfieldlen);
+ cp += otherfieldlen;
+
+ if (cp != eom)
+ return (NS_TSIG_ERROR_FORMERR);
+
+ /*
+ * Do the verification.
+ */
+
+ /* Digest the time signed and fudge. */
+ cp2 = buf;
+ PUTSHORT(0, cp2); /*%< Top 16 bits of time. */
+ PUTLONG(timesigned, cp2);
+ PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+ dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+ buf, cp2 - buf, NULL, 0);
+
+ n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+ sigstart, sigfieldlen);
+ if (n < 0)
+ return (-ns_r_badsig);
+
+ if (sigfieldlen > sizeof(state->sig))
+ return (NS_TSIG_ERROR_NO_SPACE);
+
+ memcpy(state->sig, sigstart, sigfieldlen);
+ state->siglen = sigfieldlen;
+
+ /* Verify the time. */
+ if (abs(timesigned - time(NULL)) > fudge)
+ return (-ns_r_badtime);
+
+ *msglen = recstart - msg;
+
+ if (error != NOERROR)
+ return (error);
+
+ return (0);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/herror.c b/usr/src/lib/libresolv2_joy/common/resolv/herror.c
new file mode 100644
index 0000000000..568ce3ce68
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/herror.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: herror.c,v 1.4 2005/04/27 04:56:41 sra Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <string.h>
+#include <unistd.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+const char *h_errlist[] = {
+ "Resolver Error 0 (no error)",
+ "Unknown host", /*%< 1 HOST_NOT_FOUND */
+ "Host name lookup failure", /*%< 2 TRY_AGAIN */
+ "Unknown server error", /*%< 3 NO_RECOVERY */
+ "No address associated with name", /*%< 4 NO_ADDRESS */
+};
+int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+
+#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#undef h_errno
+int h_errno;
+#endif
+
+/*%
+ * herror --
+ * print the error indicated by the h_errno value.
+ */
+void
+herror(const char *s) {
+ struct iovec iov[4], *v = iov;
+ char *t;
+
+ if (s != NULL && *s != '\0') {
+ DE_CONST(s, t);
+ v->iov_base = t;
+ v->iov_len = strlen(t);
+ v++;
+ DE_CONST(": ", t);
+ v->iov_base = t;
+ v->iov_len = 2;
+ v++;
+ }
+ DE_CONST(hstrerror(*__h_errno()), t);
+ v->iov_base = t;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ DE_CONST("\n", t);
+ v->iov_base = t;
+ v->iov_len = 1;
+ writev(STDERR_FILENO, iov, (v - iov) + 1);
+}
+
+/*%
+ * hstrerror --
+ * return the string associated with a given "host" errno value.
+ */
+const char *
+hstrerror(int err) {
+ if (err < 0)
+ return ("Resolver internal error");
+ else if (err < h_nerr)
+ return (h_errlist[err]);
+ return ("Unknown resolver error");
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/mtctxres.c b/usr/src/lib/libresolv2_joy/common/resolv/mtctxres.c
new file mode 100644
index 0000000000..2e79b1e7b4
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/mtctxres.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <port_before.h>
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv_mt.h>
+#include <irs.h>
+#include <port_after.h>
+
+#ifdef DO_PTHREADS
+static pthread_key_t key;
+static int mt_key_initialized = 0;
+
+static int __res_init_ctx(void);
+static void __res_destroy_ctx(void *);
+
+#if defined(sun) && !defined(__GNUC__)
+#pragma init (_mtctxres_init)
+#endif
+#endif
+
+static mtctxres_t sharedctx;
+
+#ifdef DO_PTHREADS
+/*
+ * Initialize the TSD key. By doing this at library load time, we're
+ * implicitly running without interference from other threads, so there's
+ * no need for locking.
+ */
+static void
+_mtctxres_init(void) {
+ int pthread_keycreate_ret;
+
+ pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
+ if (pthread_keycreate_ret == 0)
+ mt_key_initialized = 1;
+}
+#endif
+
+/*
+ * To support binaries that used the private MT-safe interface in
+ * Solaris 8, we still need to provide the __res_enable_mt()
+ * and __res_disable_mt() entry points. They're do-nothing routines.
+ */
+int
+__res_enable_mt(void) {
+ return (-1);
+}
+
+int
+__res_disable_mt(void) {
+ return (0);
+}
+
+#ifdef DO_PTHREADS
+static int
+__res_init_ctx(void) {
+
+ mtctxres_t *mt;
+ int ret;
+
+
+ if (pthread_getspecific(key) != 0) {
+ /* Already exists */
+ return (0);
+ }
+
+ if ((mt = malloc(sizeof (mtctxres_t))) == 0) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ memset(mt, 0, sizeof (mtctxres_t));
+
+ if ((ret = pthread_setspecific(key, mt)) != 0) {
+ free(mt);
+ errno = ret;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+__res_destroy_ctx(void *value) {
+
+ mtctxres_t *mt = (mtctxres_t *)value;
+
+ if (mt != 0)
+ free(mt);
+}
+#endif
+
+mtctxres_t *
+___mtctxres(void) {
+#ifdef DO_PTHREADS
+ mtctxres_t *mt;
+
+ /*
+ * This if clause should only be executed if we are linking
+ * statically. When linked dynamically _mtctxres_init() should
+ * be called at binding time due the #pragma above.
+ */
+ if (!mt_key_initialized) {
+ static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
+ if (pthread_mutex_lock(&keylock) == 0) {
+ _mtctxres_init();
+ (void) pthread_mutex_unlock(&keylock);
+ }
+ }
+
+ /*
+ * If we have already been called in this thread return the existing
+ * context. Otherwise recreat a new context and return it. If
+ * that fails return a global context.
+ */
+ if (mt_key_initialized) {
+ if (((mt = pthread_getspecific(key)) != 0) ||
+ (__res_init_ctx() == 0 &&
+ (mt = pthread_getspecific(key)) != 0)) {
+ return (mt);
+ }
+ }
+#endif
+ return (&sharedctx);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_comp.c b/usr/src/lib/libresolv2_joy/common/resolv/res_comp.c
new file mode 100644
index 0000000000..c82bf01eb8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_comp.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_comp.c,v 1.5 2005/07/28 06:51:50 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "port_after.h"
+
+#ifndef ORIGINAL_ISC_CODE
+#pragma weak __dn_skipname = dn_skipname
+#pragma weak __res_dnok = res_dnok
+#pragma weak __res_hnok = res_hnok
+#pragma weak __res_mailok = res_mailok
+#pragma weak __res_ownok = res_ownok
+#endif /* ORIGINAL_ISC_CODE */
+
+/*%
+ * Expand compressed domain name 'src' to full domain name.
+ *
+ * \li 'msg' is a pointer to the begining of the message,
+ * \li 'eom' points to the first location after the message,
+ * \li 'dst' is a pointer to a buffer of size 'dstsiz' for the result.
+ * \li Return size of compressed name or -1 if there was an error.
+ */
+int
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+ char *dst, int dstsiz)
+{
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+ if (n > 0 && dst[0] == '.')
+ dst[0] = '\0';
+ return (n);
+}
+
+/*%
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ *
+ * \li Return the size of the compressed name or -1.
+ * \li 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, int dstsiz,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ return (ns_name_compress(src, dst, (size_t)dstsiz,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr));
+}
+
+
+/*%
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+dn_skipname(const u_char *ptr, const u_char *eom) {
+ const u_char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return (-1);
+ return (ptr - saveptr);
+}
+
+/*%
+ * Verify that a domain name uses an acceptable character set.
+ *
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#ifdef SUNW_HNOK_UNDERSCORE
+#define underscorechar(c) ((c) == 0x5f)
+#endif /* SUNW_HNOK_UNDERSCORE */
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#ifdef SUNW_HNOK_UNDERSCORE
+#define middlechar(c) (borderchar(c) || hyphenchar(c) || underscorechar(c))
+#else
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#endif /* SUNW_HNOK_UNDERSCORE */
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+int
+res_hnok(const char *dn) {
+ int pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ (void)NULL;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/*%
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(const char *dn) {
+ if (asterchar(dn[0])) {
+ if (periodchar(dn[1]))
+ return (res_hnok(dn+2));
+ if (dn[1] == '\0')
+ return (1);
+ }
+ return (res_hnok(dn));
+}
+
+/*%
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(const char *dn) {
+ int ch, escaped = 0;
+
+ /* "." is a valid missing representation */
+ if (*dn == '\0')
+ return (1);
+
+ /* otherwise <label>.<hostname> */
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (!escaped && periodchar(ch))
+ break;
+ if (escaped)
+ escaped = 0;
+ else if (bslashchar(ch))
+ escaped = 1;
+ }
+ if (periodchar(ch))
+ return (res_hnok(dn));
+ return (0);
+}
+
+/*%
+ * This function is quite liberal, since RFC1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(const char *dn) {
+ int ch;
+
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
+ return (0);
+ return (1);
+}
+
+#ifdef BIND_4_COMPAT
+/*%
+ * This module must export the following externally-visible symbols:
+ * ___putlong
+ * ___putshort
+ * __getlong
+ * __getshort
+ * Note that one _ comes from C and the others come from us.
+ */
+
+#ifdef SOLARIS2
+#ifdef __putlong
+#undef __putlong
+#endif
+#ifdef __putshort
+#undef __putshort
+#endif
+#pragma weak putlong = __putlong
+#pragma weak putshort = __putshort
+#endif /* SOLARIS2 */
+
+void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+#ifndef __ultrix__
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#endif /*__ultrix__*/
+#endif /*BIND_4_COMPAT*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_data.c b/usr/src/lib/libresolv2_joy/common/resolv/res_data.c
new file mode 100644
index 0000000000..f1e0dd030b
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_data.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#ifndef ORIGINAL_ISC_CODE
+#pragma weak __fp_nquery = fp_nquery
+#pragma weak __fp_query = fp_query
+#pragma weak __p_query = p_query
+#pragma weak __hostalias = hostalias
+#pragma weak __res_randomid = res_randomid
+#endif
+
+const char *_res_opcodes[] = {
+ "QUERY",
+ "IQUERY",
+ "CQUERYM",
+ "CQUERYU", /*%< experimental */
+ "NOTIFY", /*%< experimental */
+ "UPDATE",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "ZONEINIT",
+ "ZONEREF",
+};
+
+#ifdef BIND_UPDATE
+const char *_res_sectioncodes[] = {
+ "ZONE",
+ "PREREQUISITES",
+ "UPDATE",
+ "ADDITIONAL",
+};
+#endif
+
+#undef _res
+#ifndef __BIND_NOSTATIC
+struct __res_state _res
+# if defined(__BIND_RES_TEXT)
+ = { RES_TIMEOUT, } /*%< Motorola, et al. */
+# endif
+ ;
+
+#ifdef ORIGINAL_ISC_CODE
+#if defined(DO_PTHREADS) || defined(__linux)
+#define _res (*__res_state())
+#endif
+#endif
+
+/* Proto. */
+
+int res_ourserver_p(const res_state, const struct sockaddr_in *);
+
+int
+res_init(void) {
+ extern int __res_vinit(res_state, int);
+
+ /*
+ * These three fields used to be statically initialized. This made
+ * it hard to use this code in a shared library. It is necessary,
+ * now that we're doing dynamic initialization here, that we preserve
+ * the old semantics: if an application modifies one of these three
+ * fields of _res before res_init() is called, res_init() will not
+ * alter them. Of course, if an application is setting them to
+ * _zero_ before calling res_init(), hoping to override what used
+ * to be the static default, we can't detect it and unexpected results
+ * will follow. Zero for any of these fields would make no sense,
+ * so one can safely assume that the applications were already getting
+ * unexpected results.
+ *
+ * _res.options is tricky since some apps were known to diddle the bits
+ * before res_init() was first called. We can't replicate that semantic
+ * with dynamic initialization (they may have turned bits off that are
+ * set in RES_DEFAULT). Our solution is to declare such applications
+ * "broken". They could fool us by setting RES_INIT but none do (yet).
+ */
+ if (!_res.retrans)
+ _res.retrans = RES_TIMEOUT;
+ if (!_res.retry)
+ _res.retry = 4;
+ if (!(_res.options & RES_INIT))
+ _res.options = RES_DEFAULT;
+
+ /*
+ * This one used to initialize implicitly to zero, so unless the app
+ * has set it to something in particular, we can randomize it now.
+ */
+ if (!_res.id)
+ _res.id = res_nrandomid(&_res);
+
+ return (__res_vinit(&_res, 1));
+}
+
+void
+p_query(const u_char *msg) {
+ fp_query(msg, stdout);
+}
+
+void
+fp_query(const u_char *msg, FILE *file) {
+ fp_nquery(msg, PACKETSZ, file);
+}
+
+void
+fp_nquery(const u_char *msg, int len, FILE *file) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1)
+ return;
+
+ res_pquery(&_res, msg, len, file);
+}
+
+int
+res_mkquery(int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nmkquery(&_res, op, dname, class, type,
+ data, datalen,
+ newrr_in, buf, buflen));
+}
+
+int
+res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nmkupdate(&_res, rrecp_in, buf, buflen));
+}
+
+int
+res_query(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer buffer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+ return (res_nquery(&_res, name, class, type, answer, anslen));
+}
+
+void
+res_send_setqhook(res_send_qhook hook) {
+ _res.qhook = hook;
+}
+
+void
+res_send_setrhook(res_send_rhook hook) {
+ _res.rhook = hook;
+}
+
+int
+res_isourserver(const struct sockaddr_in *inp) {
+ return (res_ourserver_p(&_res, inp));
+}
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsend(&_res, buf, buflen, ans, anssiz));
+}
+
+int
+res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
+ u_char *ans, int anssiz)
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ /* errno should have been set by res_init() in this case. */
+ return (-1);
+ }
+
+ return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
+}
+
+void
+res_close(void) {
+ res_nclose(&_res);
+}
+
+int
+res_update(ns_updrec *rrecp_in) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nupdate(&_res, rrecp_in, NULL));
+}
+
+int
+res_search(const char *name, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nsearch(&_res, name, class, type, answer, anslen));
+}
+
+int
+res_querydomain(const char *name,
+ const char *domain,
+ int class, int type, /*!< class and type of query */
+ u_char *answer, /*!< buffer to put answer */
+ int anslen) /*!< size of answer */
+{
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nquerydomain(&_res, name, domain,
+ class, type,
+ answer, anslen));
+}
+
+u_int
+res_randomid(void) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nrandomid(&_res));
+}
+
+const char *
+hostalias(const char *name) {
+ static char abuf[MAXDNAME];
+
+ return (res_hostalias(&_res, name, abuf, sizeof abuf));
+}
+
+#ifdef ultrix
+int
+local_hostname_length(const char *hostname) {
+ int len_host, len_domain;
+
+ if (!*_res.defdname)
+ res_init();
+ len_host = strlen(hostname);
+ len_domain = strlen(_res.defdname);
+ if (len_host > len_domain &&
+ !strcasecmp(hostname + len_host - len_domain, _res.defdname) &&
+ hostname[len_host - len_domain - 1] == '.')
+ return (len_host - len_domain - 1);
+ return (0);
+}
+#endif /*ultrix*/
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_debug.c b/usr/src/lib/libresolv2_joy/common/resolv/res_debug.c
new file mode 100644
index 0000000000..e11fb29612
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_debug.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Portions Copyright (C) 2004, 2005, 2008, 2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <resolv_mt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+extern const char *_res_opcodes[];
+extern const char *_res_sectioncodes[];
+
+#ifndef ORIGINAL_ISC_CODE
+#pragma weak __dn_count_labels = dn_count_labels
+#pragma weak __fp_resstat = fp_resstat
+#pragma weak __loc_aton = loc_aton
+#pragma weak __loc_ntoa = loc_ntoa
+#pragma weak __p_cdname = p_cdname
+#pragma weak __p_class = p_class
+#pragma weak __p_section = p_section
+#pragma weak __p_time = p_time
+#pragma weak __p_type = p_type
+#pragma weak __sym_ntop = sym_ntop
+#pragma weak __sym_ntos = sym_ntos
+#pragma weak __sym_ston = sym_ston
+#endif /* ORIGINAL_ISC_CODE */
+
+/*%
+ * Print the current options.
+ */
+void
+fp_resstat(const res_state statp, FILE *file) {
+ u_long mask;
+
+ fprintf(file, ";; res options:");
+ for (mask = 1; mask != 0U; mask <<= 1)
+ if (statp->options & mask)
+ fprintf(file, " %s", p_option(mask));
+ putc('\n', file);
+}
+
+static void
+do_section(const res_state statp,
+ ns_msg *handle, ns_sect section,
+ int pflag, FILE *file)
+{
+ int n, sflag, rrnum;
+ static int buflen = 2048;
+ char *buf;
+ ns_opcode opcode;
+ ns_rr rr;
+
+ /*
+ * Print answer records.
+ */
+ sflag = (statp->pfcode & pflag);
+ if (statp->pfcode && !sflag)
+ return;
+
+ buf = malloc(buflen);
+ if (buf == NULL) {
+ fprintf(file, ";; memory allocation failure\n");
+ return;
+ }
+
+ opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
+ rrnum = 0;
+ for (;;) {
+ if (ns_parserr(handle, section, rrnum, &rr)) {
+ if (errno != ENODEV)
+ fprintf(file, ";; ns_parserr: %s\n",
+ strerror(errno));
+ else if (rrnum > 0 && sflag != 0 &&
+ (statp->pfcode & RES_PRF_HEAD1))
+ putc('\n', file);
+ goto cleanup;
+ }
+ if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+ fprintf(file, ";; %s SECTION:\n",
+ p_section(section, opcode));
+ if (section == ns_s_qd)
+ fprintf(file, ";;\t%s, type = %s, class = %s\n",
+ ns_rr_name(rr),
+ p_type(ns_rr_type(rr)),
+ p_class(ns_rr_class(rr)));
+ else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
+ u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
+ u_int32_t ttl = ns_rr_ttl(rr);
+
+ fprintf(file,
+ "; EDNS: version: %u, udp=%u, flags=%04x\n",
+ (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
+
+ while (rdatalen >= 4) {
+ const u_char *cp = ns_rr_rdata(rr);
+ int i;
+
+ GETSHORT(optcode, cp);
+ GETSHORT(optlen, cp);
+
+ if (optcode == NS_OPT_NSID) {
+ fputs("; NSID: ", file);
+ if (optlen == 0) {
+ fputs("; NSID\n", file);
+ } else {
+ fputs("; NSID: ", file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%02x ",
+ cp[i]);
+ fputs(" (",file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%c",
+ isprint(cp[i])?
+ cp[i] : '.');
+ fputs(")\n", file);
+ }
+ } else {
+ if (optlen == 0) {
+ fprintf(file, "; OPT=%u\n",
+ optcode);
+ } else {
+ fprintf(file, "; OPT=%u: ",
+ optcode);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%02x ",
+ cp[i]);
+ fputs(" (",file);
+ for (i = 0; i < optlen; i++)
+ fprintf(file, "%c",
+ isprint(cp[i]) ?
+ cp[i] : '.');
+ fputs(")\n", file);
+ }
+ }
+ rdatalen -= 4 + optlen;
+ }
+ } else {
+ n = ns_sprintrr(handle, &rr, NULL, NULL,
+ buf, buflen);
+ if (n < 0) {
+ if (errno == ENOSPC) {
+ free(buf);
+ buf = NULL;
+ if (buflen < 131072)
+ buf = malloc(buflen += 1024);
+ if (buf == NULL) {
+ fprintf(file,
+ ";; memory allocation failure\n");
+ return;
+ }
+ continue;
+ }
+ fprintf(file, ";; ns_sprintrr: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ fputs(buf, file);
+ fputc('\n', file);
+ }
+ rrnum++;
+ }
+ cleanup:
+ if (buf != NULL)
+ free(buf);
+}
+
+/*%
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+ ns_msg handle;
+ int qdcount, ancount, nscount, arcount;
+ u_int opcode, rcode, id;
+
+ if (ns_initparse(msg, len, &handle) < 0) {
+ fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
+ return;
+ }
+ opcode = ns_msg_getflag(handle, ns_f_opcode);
+ rcode = ns_msg_getflag(handle, ns_f_rcode);
+ id = ns_msg_id(handle);
+ qdcount = ns_msg_count(handle, ns_s_qd);
+ ancount = ns_msg_count(handle, ns_s_an);
+ nscount = ns_msg_count(handle, ns_s_ns);
+ arcount = ns_msg_count(handle, ns_s_ar);
+
+ /*
+ * Print header fields.
+ */
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+ fprintf(file,
+ ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
+ _res_opcodes[opcode], p_rcode(rcode), id);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+ putc(';', file);
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+ fprintf(file, "; flags:");
+ if (ns_msg_getflag(handle, ns_f_qr))
+ fprintf(file, " qr");
+ if (ns_msg_getflag(handle, ns_f_aa))
+ fprintf(file, " aa");
+ if (ns_msg_getflag(handle, ns_f_tc))
+ fprintf(file, " tc");
+ if (ns_msg_getflag(handle, ns_f_rd))
+ fprintf(file, " rd");
+ if (ns_msg_getflag(handle, ns_f_ra))
+ fprintf(file, " ra");
+ if (ns_msg_getflag(handle, ns_f_z))
+ fprintf(file, " ??");
+ if (ns_msg_getflag(handle, ns_f_ad))
+ fprintf(file, " ad");
+ if (ns_msg_getflag(handle, ns_f_cd))
+ fprintf(file, " cd");
+ }
+ if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+ fprintf(file, "; %s: %d",
+ p_section(ns_s_qd, opcode), qdcount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_an, opcode), ancount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ns, opcode), nscount);
+ fprintf(file, ", %s: %d",
+ p_section(ns_s_ar, opcode), arcount);
+ }
+ if ((!statp->pfcode) || (statp->pfcode &
+ (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+ putc('\n',file);
+ }
+ /*
+ * Print the various sections.
+ */
+ do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
+ do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
+ do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
+ do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+ if (qdcount == 0 && ancount == 0 &&
+ nscount == 0 && arcount == 0)
+ putc('\n', file);
+}
+
+const u_char *
+p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
+ char name[MAXDNAME];
+ int n;
+
+ if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+ return (NULL);
+ if (name[0] == '\0')
+ putc('.', file);
+ else
+ fputs(name, file);
+ return (cp + n);
+}
+
+const u_char *
+p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
+ return (p_cdnname(cp, msg, PACKETSZ, file));
+}
+
+/*%
+ * Return a fully-qualified domain name from a compressed name (with
+ length supplied). */
+
+const u_char *
+p_fqnname(cp, msg, msglen, name, namelen)
+ const u_char *cp, *msg;
+ int msglen;
+ char *name;
+ int namelen;
+{
+ int n, newlen;
+
+ if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+ return (NULL);
+ newlen = strlen(name);
+ if (newlen == 0 || name[newlen - 1] != '.') {
+ if (newlen + 1 >= namelen) /*%< Lack space for final dot */
+ return (NULL);
+ else
+ strcpy(name + newlen, ".");
+ }
+ return (cp + n);
+}
+
+/* XXX: the rest of these functions need to become length-limited, too. */
+
+const u_char *
+p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
+ char name[MAXDNAME];
+ const u_char *n;
+
+ n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+ if (n == NULL)
+ return (NULL);
+ fputs(name, file);
+ return (n);
+}
+
+/*%
+ * Names of RR classes and qclasses. Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class. (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+ {C_IN, "IN", (char *)0},
+ {C_CHAOS, "CH", (char *)0},
+ {C_CHAOS, "CHAOS", (char *)0},
+ {C_HS, "HS", (char *)0},
+ {C_HS, "HESIOD", (char *)0},
+ {C_ANY, "ANY", (char *)0},
+ {C_NONE, "NONE", (char *)0},
+ {C_IN, (char *)0, (char *)0}
+};
+
+/*%
+ * Names of message sections.
+ */
+const struct res_sym __p_default_section_syms[] = {
+ {ns_s_qd, "QUERY", (char *)0},
+ {ns_s_an, "ANSWER", (char *)0},
+ {ns_s_ns, "AUTHORITY", (char *)0},
+ {ns_s_ar, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __p_update_section_syms[] = {
+ {S_ZONE, "ZONE", (char *)0},
+ {S_PREREQ, "PREREQUISITE", (char *)0},
+ {S_UPDATE, "UPDATE", (char *)0},
+ {S_ADDT, "ADDITIONAL", (char *)0},
+ {0, (char *)0, (char *)0}
+};
+
+const struct res_sym __p_key_syms[] = {
+ {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"},
+ {NS_ALG_DH, "DH", "Diffie Hellman"},
+ {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"},
+ {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"},
+ {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"},
+ {0, NULL, NULL}
+};
+
+const struct res_sym __p_cert_syms[] = {
+ {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"},
+ {cert_t_spki, "SPKI", "SPKI certificate"},
+ {cert_t_pgp, "PGP", "PGP certificate"},
+ {cert_t_url, "URL", "URL Private"},
+ {cert_t_oid, "OID", "OID Private"},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of RR types and qtypes. Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type. (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+ {ns_t_a, "A", "address"},
+ {ns_t_ns, "NS", "name server"},
+ {ns_t_md, "MD", "mail destination (deprecated)"},
+ {ns_t_mf, "MF", "mail forwarder (deprecated)"},
+ {ns_t_cname, "CNAME", "canonical name"},
+ {ns_t_soa, "SOA", "start of authority"},
+ {ns_t_mb, "MB", "mailbox"},
+ {ns_t_mg, "MG", "mail group member"},
+ {ns_t_mr, "MR", "mail rename"},
+ {ns_t_null, "NULL", "null"},
+ {ns_t_wks, "WKS", "well-known service (deprecated)"},
+ {ns_t_ptr, "PTR", "domain name pointer"},
+ {ns_t_hinfo, "HINFO", "host information"},
+ {ns_t_minfo, "MINFO", "mailbox information"},
+ {ns_t_mx, "MX", "mail exchanger"},
+ {ns_t_txt, "TXT", "text"},
+ {ns_t_rp, "RP", "responsible person"},
+ {ns_t_afsdb, "AFSDB", "DCE or AFS server"},
+ {ns_t_x25, "X25", "X25 address"},
+ {ns_t_isdn, "ISDN", "ISDN address"},
+ {ns_t_rt, "RT", "router"},
+ {ns_t_nsap, "NSAP", "nsap address"},
+ {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"},
+ {ns_t_sig, "SIG", "signature"},
+ {ns_t_key, "KEY", "key"},
+ {ns_t_px, "PX", "mapping information"},
+ {ns_t_gpos, "GPOS", "geographical position (withdrawn)"},
+ {ns_t_aaaa, "AAAA", "IPv6 address"},
+ {ns_t_loc, "LOC", "location"},
+ {ns_t_nxt, "NXT", "next valid name (unimplemented)"},
+ {ns_t_eid, "EID", "endpoint identifier (unimplemented)"},
+ {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
+ {ns_t_srv, "SRV", "server selection"},
+ {ns_t_atma, "ATMA", "ATM address (unimplemented)"},
+ {ns_t_naptr, "NAPTR", "naptr"},
+ {ns_t_kx, "KX", "key exchange"},
+ {ns_t_cert, "CERT", "certificate"},
+ {ns_t_a6, "A", "IPv6 address (experminental)"},
+ {ns_t_dname, "DNAME", "non-terminal redirection"},
+ {ns_t_opt, "OPT", "opt"},
+ {ns_t_apl, "apl", "apl"},
+ {ns_t_ds, "DS", "delegation signer"},
+ {ns_t_sshfp, "SSFP", "SSH fingerprint"},
+ {ns_t_ipseckey, "IPSECKEY", "IPSEC key"},
+ {ns_t_rrsig, "RRSIG", "rrsig"},
+ {ns_t_nsec, "NSEC", "nsec"},
+ {ns_t_dnskey, "DNSKEY", "DNS key"},
+ {ns_t_dhcid, "DHCID", "dynamic host configuration identifier"},
+ {ns_t_nsec3, "NSEC3", "nsec3"},
+ {ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
+ {ns_t_hip, "HIP", "host identity protocol"},
+ {ns_t_spf, "SPF", "sender policy framework"},
+ {ns_t_tkey, "TKEY", "tkey"},
+ {ns_t_tsig, "TSIG", "transaction signature"},
+ {ns_t_ixfr, "IXFR", "incremental zone transfer"},
+ {ns_t_axfr, "AXFR", "zone transfer"},
+ {ns_t_zxfr, "ZXFR", "compressed zone transfer"},
+ {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"},
+ {ns_t_maila, "MAILA", "mail agent (deprecated)"},
+ {ns_t_naptr, "NAPTR", "URN Naming Authority"},
+ {ns_t_kx, "KX", "Key Exchange"},
+ {ns_t_cert, "CERT", "Certificate"},
+ {ns_t_a6, "A6", "IPv6 Address"},
+ {ns_t_dname, "DNAME", "dname"},
+ {ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
+ {ns_t_opt, "OPT", "EDNS Options"},
+ {ns_t_any, "ANY", "\"any\""},
+ {ns_t_dlv, "DLV", "DNSSEC look-aside validation"},
+ {0, NULL, NULL}
+};
+
+/*%
+ * Names of DNS rcodes.
+ */
+const struct res_sym __p_rcode_syms[] = {
+ {ns_r_noerror, "NOERROR", "no error"},
+ {ns_r_formerr, "FORMERR", "format error"},
+ {ns_r_servfail, "SERVFAIL", "server failed"},
+ {ns_r_nxdomain, "NXDOMAIN", "no such domain name"},
+ {ns_r_notimpl, "NOTIMP", "not implemented"},
+ {ns_r_refused, "REFUSED", "refused"},
+ {ns_r_yxdomain, "YXDOMAIN", "domain name exists"},
+ {ns_r_yxrrset, "YXRRSET", "rrset exists"},
+ {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"},
+ {ns_r_notauth, "NOTAUTH", "not authoritative"},
+ {ns_r_notzone, "NOTZONE", "Not in zone"},
+ {ns_r_max, "", ""},
+ {ns_r_badsig, "BADSIG", "bad signature"},
+ {ns_r_badkey, "BADKEY", "bad key"},
+ {ns_r_badtime, "BADTIME", "bad time"},
+ {0, NULL, NULL}
+};
+
+int
+sym_ston(const struct res_sym *syms, const char *name, int *success) {
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (strcasecmp (name, syms->name) == 0) {
+ if (success)
+ *success = 1;
+ return (syms->number);
+ }
+ }
+ if (success)
+ *success = 0;
+ return (syms->number); /*%< The default value. */
+}
+
+const char *
+sym_ntos(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntos_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->name);
+ }
+ }
+
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+const char *
+sym_ntop(const struct res_sym *syms, int number, int *success) {
+ char *unname = sym_ntop_unname;
+
+ for ((void)NULL; syms->name != 0; syms++) {
+ if (number == syms->number) {
+ if (success)
+ *success = 1;
+ return (syms->humanname);
+ }
+ }
+ sprintf(unname, "%d", number); /*%< XXX nonreentrant */
+ if (success)
+ *success = 0;
+ return (unname);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_type(int type) {
+ int success;
+ const char *result;
+ static char typebuf[20];
+
+ result = sym_ntos(__p_type_syms, type, &success);
+ if (success)
+ return (result);
+ if (type < 0 || type > 0xffff)
+ return ("BADTYPE");
+ sprintf(typebuf, "TYPE%d", type);
+ return (typebuf);
+}
+
+/*%
+ * Return a string for the type.
+ */
+const char *
+p_section(int section, int opcode) {
+ const struct res_sym *symbols;
+
+ switch (opcode) {
+ case ns_o_update:
+ symbols = __p_update_section_syms;
+ break;
+ default:
+ symbols = __p_default_section_syms;
+ break;
+ }
+ return (sym_ntos(symbols, section, (int *)0));
+}
+
+/*%
+ * Return a mnemonic for class.
+ */
+const char *
+p_class(int class) {
+ int success;
+ const char *result;
+ static char classbuf[20];
+
+ result = sym_ntos(__p_class_syms, class, &success);
+ if (success)
+ return (result);
+ if (class < 0 || class > 0xffff)
+ return ("BADCLASS");
+ sprintf(classbuf, "CLASS%d", class);
+ return (classbuf);
+}
+
+/*%
+ * Return a mnemonic for an option
+ */
+const char *
+p_option(u_long option) {
+ char *nbuf = p_option_nbuf;
+
+ switch (option) {
+ case RES_INIT: return "init";
+ case RES_DEBUG: return "debug";
+ case RES_AAONLY: return "aaonly(unimpl)";
+ case RES_USEVC: return "usevc";
+ case RES_PRIMARY: return "primry(unimpl)";
+ case RES_IGNTC: return "igntc";
+ case RES_RECURSE: return "recurs";
+ case RES_DEFNAMES: return "defnam";
+ case RES_STAYOPEN: return "styopn";
+ case RES_DNSRCH: return "dnsrch";
+ case RES_INSECURE1: return "insecure1";
+ case RES_INSECURE2: return "insecure2";
+ case RES_NOALIASES: return "noaliases";
+ case RES_USE_INET6: return "inet6";
+#ifdef RES_USE_EDNS0 /*%< KAME extension */
+ case RES_USE_EDNS0: return "edns0";
+ case RES_NSID: return "nsid";
+#endif
+#ifdef RES_USE_DNAME
+ case RES_USE_DNAME: return "dname";
+#endif
+#ifdef RES_USE_DNSSEC
+ case RES_USE_DNSSEC: return "dnssec";
+#endif
+#ifdef RES_NOTLDQUERY
+ case RES_NOTLDQUERY: return "no-tld-query";
+#endif
+#ifdef RES_NO_NIBBLE2
+ case RES_NO_NIBBLE2: return "no-nibble2";
+#endif
+ /* XXX nonreentrant */
+ default: sprintf(nbuf, "?0x%lx?", (u_long)option);
+ return (nbuf);
+ }
+}
+
+/*%
+ * Return a mnemonic for a time to live.
+ */
+const char *
+p_time(u_int32_t value) {
+ char *nbuf = p_time_nbuf;
+
+ if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
+ sprintf(nbuf, "%u", value);
+ return (nbuf);
+}
+
+/*%
+ * Return a string for the rcode.
+ */
+const char *
+p_rcode(int rcode) {
+ return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
+}
+
+/*%
+ * Return a string for a res_sockaddr_union.
+ */
+const char *
+p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
+ char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
+
+ switch (u.sin.sin_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret);
+ break;
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
+ break;
+#endif
+ default:
+ sprintf(ret, "[af%d]", u.sin.sin_family);
+ break;
+ }
+ if (size > 0U) {
+ strncpy(buf, ret, size - 1);
+ buf[size - 1] = '0';
+ }
+ return (buf);
+}
+
+/*%
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/*% takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+ u_int8_t prec;
+{
+ char *retbuf = precsize_ntoa_retbuf;
+ unsigned long val;
+ int mantissa, exponent;
+
+ mantissa = (int)((prec >> 4) & 0x0f) % 10;
+ exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+ val = mantissa * poweroften[exponent];
+
+ (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
+ return (retbuf);
+}
+
+/*% converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
+static u_int8_t
+precsize_aton(const char **strptr) {
+ unsigned int mval = 0, cmval = 0;
+ u_int8_t retval = 0;
+ const char *cp;
+ int exponent;
+ int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit((unsigned char)*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< centimeters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/*% converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
+static u_int32_t
+latlon2ul(const char **latlonstrptr, int *which) {
+ const char *cp;
+ u_int32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit((unsigned char)*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ if (!(isdigit((unsigned char)*cp)))
+ goto fndhemi;
+
+ while (isdigit((unsigned char)*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal seconds */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /*%< invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /*%< latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /*%< longitude */
+ break;
+ default:
+ *which = 0; /*%< error */
+ break;
+ }
+
+ cp++; /*%< skip the hemisphere */
+ while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
+ cp++;
+
+ while (isspace((unsigned char)*cp)) /*%< move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+/*%
+ * converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(ascii, binary)
+ const char *ascii;
+ u_char *binary;
+{
+ const char *cp, *maxcp;
+ u_char *bcp;
+
+ u_int32_t latit = 0, longit = 0, alt = 0;
+ u_int32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ u_int8_t hp = 0x16; /*%< default = 1e6 cm = 10000.00m = 10km */
+ u_int8_t vp = 0x13; /*%< default = 1e3 cm = 10.00m */
+ u_int8_t siz = 0x12; /*%< default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = ascii;
+ maxcp = cp + strlen(ascii);
+
+ lltemp1 = latlon2ul(&cp, &which1);
+
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /*%< 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
+ latit = lltemp1;
+ longit = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
+ longit = lltemp1;
+ latit = lltemp2;
+ } else { /*%< some kind of brokenness */
+ return (0);
+ }
+ break;
+ default: /*%< we didn't get one of each */
+ return (0);
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit((unsigned char)*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /*%< decimal meters */
+ cp++;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit((unsigned char)*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ siz = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ hp = precsize_aton(&cp);
+
+ while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
+ cp++;
+
+ while (isspace((unsigned char)*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ vp = precsize_aton(&cp);
+
+ defaults:
+
+ bcp = binary;
+ *bcp++ = (u_int8_t) 0; /*%< version byte */
+ *bcp++ = siz;
+ *bcp++ = hp;
+ *bcp++ = vp;
+ PUTLONG(latit,bcp);
+ PUTLONG(longit,bcp);
+ PUTLONG(alt,bcp);
+
+ return (16); /*%< size of RR in octets */
+}
+
+/*% takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(binary, ascii)
+ const u_char *binary;
+ char *ascii;
+{
+ static const char *error = "?";
+ static char tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+ const u_char *cp = binary;
+
+ int latdeg, latmin, latsec, latsecfrac;
+ int longdeg, longmin, longsec, longsecfrac;
+ char northsouth, eastwest;
+ const char *altsign;
+ int altmeters, altfrac;
+
+ const u_int32_t referencealt = 100000 * 100;
+
+ int32_t latval, longval, altval;
+ u_int32_t templ;
+ u_int8_t sizeval, hpval, vpval, versionval;
+
+ char *sizestr, *hpstr, *vpstr;
+
+ versionval = *cp++;
+
+ if (ascii == NULL)
+ ascii = tmpbuf;
+
+ if (versionval) {
+ (void) sprintf(ascii, "; error: unknown LOC RR version");
+ return (ascii);
+ }
+
+ sizeval = *cp++;
+
+ hpval = *cp++;
+ vpval = *cp++;
+
+ GETLONG(templ, cp);
+ latval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ longval = (templ - ((unsigned)1<<31));
+
+ GETLONG(templ, cp);
+ if (templ < referencealt) { /*%< below WGS 84 spheroid */
+ altval = referencealt - templ;
+ altsign = "-";
+ } else {
+ altval = templ - referencealt;
+ altsign = "";
+ }
+
+ if (latval < 0) {
+ northsouth = 'S';
+ latval = -latval;
+ } else
+ northsouth = 'N';
+
+ latsecfrac = latval % 1000;
+ latval = latval / 1000;
+ latsec = latval % 60;
+ latval = latval / 60;
+ latmin = latval % 60;
+ latval = latval / 60;
+ latdeg = latval;
+
+ if (longval < 0) {
+ eastwest = 'W';
+ longval = -longval;
+ } else
+ eastwest = 'E';
+
+ longsecfrac = longval % 1000;
+ longval = longval / 1000;
+ longsec = longval % 60;
+ longval = longval / 60;
+ longmin = longval % 60;
+ longval = longval / 60;
+ longdeg = longval;
+
+ altfrac = altval % 100;
+ altmeters = (altval / 100);
+
+ sizestr = strdup(precsize_ntoa(sizeval));
+ hpstr = strdup(precsize_ntoa(hpval));
+ vpstr = strdup(precsize_ntoa(vpval));
+
+ sprintf(ascii,
+ "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
+ latdeg, latmin, latsec, latsecfrac, northsouth,
+ longdeg, longmin, longsec, longsecfrac, eastwest,
+ altsign, altmeters, altfrac,
+ (sizestr != NULL) ? sizestr : error,
+ (hpstr != NULL) ? hpstr : error,
+ (vpstr != NULL) ? vpstr : error);
+
+ if (sizestr != NULL)
+ free(sizestr);
+ if (hpstr != NULL)
+ free(hpstr);
+ if (vpstr != NULL)
+ free(vpstr);
+
+ return (ascii);
+}
+
+
+/*% Return the number of DNS hierarchy levels in the name. */
+int
+dn_count_labels(const char *name) {
+ int i, len, count;
+
+ len = strlen(name);
+ for (i = 0, count = 0; i < len; i++) {
+ /* XXX need to check for \. or use named's nlabels(). */
+ if (name[i] == '.')
+ count++;
+ }
+
+ /* don't count initial wildcard */
+ if (name[0] == '*')
+ if (count)
+ count--;
+
+ /* don't count the null label for root. */
+ /* if terminating '.' not found, must adjust */
+ /* count to include last label */
+ if (len > 0 && name[len-1] != '.')
+ count++;
+ return (count);
+}
+
+/*%
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+p_secstodate (u_long secs) {
+ char *output = p_secstodate_output;
+ time_t clock = secs;
+ struct tm *time;
+#ifdef HAVE_TIME_R
+ struct tm res;
+
+ time = gmtime_r(&clock, &res);
+#else
+ time = gmtime(&clock);
+#endif
+ time->tm_year += 1900;
+ time->tm_mon += 1;
+ sprintf(output, "%04d%02d%02d%02d%02d%02d",
+ time->tm_year, time->tm_mon, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
+ return (output);
+}
+
+u_int16_t
+res_nametoclass(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_class_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "CLASS", 5) != 0 ||
+ !isdigit((unsigned char)buf[5]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 5, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+u_int16_t
+res_nametotype(const char *buf, int *successp) {
+ unsigned long result;
+ char *endptr;
+ int success;
+
+ result = sym_ston(__p_type_syms, buf, &success);
+ if (success)
+ goto done;
+
+ if (strncasecmp(buf, "type", 4) != 0 ||
+ !isdigit((unsigned char)buf[4]))
+ goto done;
+ errno = 0;
+ result = strtoul(buf + 4, &endptr, 10);
+ if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
+ success = 1;
+ done:
+ if (successp)
+ *successp = success;
+ return (result);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_debug.h b/usr/src/lib/libresolv2_joy/common/resolv/res_debug.h
new file mode 100644
index 0000000000..c28171d7c8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_debug.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+# define Dprint(cond, args) /*empty*/
+# define DprintQ(cond, args, query, size) /*empty*/
+# define Aerror(statp, file, string, error, address) /*empty*/
+# define Perror(statp, file, string, error) /*empty*/
+#else
+# define Dprint(cond, args) if (cond) {fprintf args;} else {}
+# define DprintQ(cond, args, query, size) if (cond) {\
+ fprintf args;\
+ res_pquery(statp, query, size, stdout);\
+ } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_findzonecut.c b/usr/src/lib/libresolv2_joy/common/resolv/res_findzonecut.c
new file mode 100644
index 0000000000..431c0262c1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_findzonecut.c
@@ -0,0 +1,722 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "port_after.h"
+
+#include <resolv_joy.h>
+
+/* Data structures. */
+
+typedef struct rr_a {
+ LINK(struct rr_a) link;
+ union res_sockaddr_union addr;
+} rr_a;
+typedef LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+ LINK(struct rr_ns) link;
+ const char * name;
+ unsigned int flags;
+ rrset_a addrs;
+} rr_ns;
+typedef LIST(rr_ns) rrset_ns;
+
+#define RR_NS_HAVE_V4 0x01
+#define RR_NS_HAVE_V6 0x02
+
+/* Forward. */
+
+static int satisfy(res_state, const char *, rrset_ns *,
+ union res_sockaddr_union *, int);
+static int add_addrs(res_state, rr_ns *,
+ union res_sockaddr_union *, int);
+static int get_soa(res_state, const char *, ns_class, int,
+ char *, size_t, char *, size_t,
+ rrset_ns *);
+static int get_ns(res_state, const char *, ns_class, int, rrset_ns *);
+static int get_glue(res_state, ns_class, int, rrset_ns *);
+static int save_ns(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rrset_ns *);
+static int save_a(res_state, ns_msg *, ns_sect,
+ const char *, ns_class, int, rr_ns *);
+static void free_nsrrset(rrset_ns *);
+static void free_nsrr(rrset_ns *, rr_ns *);
+static rr_ns * find_ns(rrset_ns *, const char *);
+static int do_query(res_state, const char *, ns_class, ns_type,
+ u_char *, ns_msg *);
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+/*%
+ * find enclosing zone for a <dname,class>, and some server addresses
+ *
+ * parameters:
+ *\li res - resolver context to work within (is modified)
+ *\li dname - domain name whose enclosing zone is desired
+ *\li class - class of dname (and its enclosing zone)
+ *\li zname - found zone name
+ *\li zsize - allocated size of zname
+ *\li addrs - found server addresses
+ *\li naddrs - max number of addrs
+ *
+ * return values:
+ *\li < 0 - an error occurred (check errno)
+ *\li = 0 - zname is now valid, but addrs[] wasn't changed
+ *\li > 0 - zname is now valid, and return value is number of addrs[] found
+ *
+ * notes:
+ *\li this function calls res_nsend() which means it depends on correctly
+ * functioning recursive nameservers (usually defined in /etc/resolv.conf
+ * or its local equivilent).
+ *
+ *\li we start by asking for an SOA<dname,class>. if we get one as an
+ * answer, that just means <dname,class> is a zone top, which is fine.
+ * more than likely we'll be told to go pound sand, in the form of a
+ * negative answer.
+ *
+ *\li note that we are not prepared to deal with referrals since that would
+ * only come from authority servers and our correctly functioning local
+ * recursive server would have followed the referral and got us something
+ * more definite.
+ *
+ *\li if the authority section contains an SOA, this SOA should also be the
+ * closest enclosing zone, since any intermediary zone cuts would've been
+ * returned as referrals and dealt with by our correctly functioning local
+ * recursive name server. but an SOA in the authority section should NOT
+ * match our dname (since that would have been returned in the answer
+ * section). an authority section SOA has to be "above" our dname.
+ *
+ *\li however, since authority section SOA's were once optional, it's
+ * possible that we'll have to go hunting for the enclosing SOA by
+ * ripping labels off the front of our dname -- this is known as "doing
+ * it the hard way."
+ *
+ *\li ultimately we want some server addresses, which are ideally the ones
+ * pertaining to the SOA.MNAME, but only if there is a matching NS RR.
+ * so the second phase (after we find an SOA) is to go looking for the
+ * NS RRset for that SOA's zone.
+ *
+ *\li no answer section processed by this code is allowed to contain CNAME
+ * or DNAME RR's. for the SOA query this means we strip a label and
+ * keep going. for the NS and A queries this means we just give up.
+ */
+
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+{
+ int result, i;
+ union res_sockaddr_union *u;
+
+
+ opts |= RES_IPV4ONLY;
+ opts &= ~RES_IPV6ONLY;
+
+ u = calloc(naddrs, sizeof(*u));
+ if (u == NULL)
+ return(-1);
+
+ result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
+ u, naddrs);
+
+ for (i = 0; i < result; i++) {
+ addrs[i] = u[i].sin.sin_addr;
+ }
+ free(u);
+ return (result);
+}
+
+int
+res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, union res_sockaddr_union *addrs,
+ int naddrs)
+{
+ char mname[NS_MAXDNAME];
+ u_long save_pfcode;
+ rrset_ns nsrrs;
+ int n;
+
+ DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
+ dname, p_class(class), (long)zsize, naddrs));
+ save_pfcode = statp->pfcode;
+ statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
+ RES_PRF_QUES | RES_PRF_ANS |
+ RES_PRF_AUTH | RES_PRF_ADD;
+ INIT_LIST(nsrrs);
+
+ DPRINTF(("get the soa, and see if it has enough glue"));
+ if ((n = get_soa(statp, dname, class, opts, zname, zsize,
+ mname, sizeof mname, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the ns rrset and see if it has enough glue"));
+ if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
+ ((opts & RES_EXHAUSTIVE) == 0 &&
+ (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+ goto done;
+
+ DPRINTF(("get the missing glue and see if it's finally enough"));
+ if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
+ n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+ DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+ free_nsrrset(&nsrrs);
+ statp->pfcode = save_pfcode;
+ return (n);
+}
+
+/* Private. */
+
+static int
+satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_ns *nsrr;
+ int n, x;
+
+ n = 0;
+ nsrr = find_ns(nsrrsp, mname);
+ if (nsrr != NULL) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ for (nsrr = HEAD(*nsrrsp);
+ nsrr != NULL && naddrs > 0;
+ nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, mname) != 1) {
+ x = add_addrs(statp, nsrr, addrs, naddrs);
+ addrs += x;
+ naddrs -= x;
+ n += x;
+ }
+ DPRINTF(("satisfy(%s): %d", mname, n));
+ return (n);
+}
+
+static int
+add_addrs(res_state statp, rr_ns *nsrr,
+ union res_sockaddr_union *addrs, int naddrs)
+{
+ rr_a *arr;
+ int n = 0;
+
+ for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
+ if (naddrs <= 0)
+ return (0);
+ *addrs++ = arr->addr;
+ naddrs--;
+ n++;
+ }
+ DPRINTF(("add_addrs: %d", n));
+ return (n);
+}
+
+static int
+get_soa(res_state statp, const char *dname, ns_class class, int opts,
+ char *zname, size_t zsize, char *mname, size_t msize,
+ rrset_ns *nsrrsp)
+{
+ char tname[NS_MAXDNAME];
+ u_char *resp = NULL;
+ int n, i, ancount, nscount;
+ ns_sect sect;
+ ns_msg msg;
+ u_int rcode;
+
+ /*
+ * Find closest enclosing SOA, even if it's for the root zone.
+ */
+
+ /* First canonicalize dname (exactly one unescaped trailing "."). */
+ if (ns_makecanon(dname, tname, sizeof tname) < 0)
+ goto cleanup;
+ dname = tname;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ goto cleanup;
+
+ /* Now grovel the subdomains, hunting for an SOA answer or auth. */
+ for (;;) {
+ /* Leading or inter-label '.' are skipped here. */
+ while (*dname == '.')
+ dname++;
+
+ /* Is there an SOA? */
+ n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+ if (n < 0) {
+ DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+ dname, p_class(class), n));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF(("get_soa: CNAME or DNAME found"));
+ sect = ns_s_max, n = 0;
+ } else {
+ rcode = ns_msg_getflag(msg, ns_f_rcode);
+ ancount = ns_msg_count(msg, ns_s_an);
+ nscount = ns_msg_count(msg, ns_s_ns);
+ if (ancount > 0 && rcode == ns_r_noerror)
+ sect = ns_s_an, n = ancount;
+ else if (nscount > 0)
+ sect = ns_s_ns, n = nscount;
+ else
+ sect = ns_s_max, n = 0;
+ }
+ for (i = 0; i < n; i++) {
+ const char *t;
+ const u_char *rdata;
+ ns_rr rr;
+
+ if (ns_parserr(&msg, sect, i, &rr) < 0) {
+ DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ goto cleanup;
+ }
+ if (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname)
+ break;
+ if (ns_rr_type(rr) != ns_t_soa ||
+ ns_rr_class(rr) != class)
+ continue;
+ t = ns_rr_name(rr);
+ switch (sect) {
+ case ns_s_an:
+ if (ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samedomain('%s', '%s') == 0",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ case ns_s_ns:
+ if (ns_samename(dname, t) == 1 ||
+ ns_samedomain(dname, t) == 0) {
+ DPRINTF(
+ ("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+ dname, t)
+ );
+ errno = EPROTOTYPE;
+ goto cleanup;
+ }
+ break;
+ default:
+ abort();
+ }
+ if (strlen(t) + 1 > zsize) {
+ DPRINTF(("get_soa: zname(%lu) too small (%lu)",
+ (unsigned long)zsize,
+ (unsigned long)strlen(t) + 1));
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ strcpy(zname, t);
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+ mname, msize) < 0) {
+ DPRINTF(("get_soa: ns_name_uncompress failed")
+ );
+ goto cleanup;
+ }
+ if (save_ns(statp, &msg, ns_s_ns,
+ zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_soa: save_ns failed"));
+ goto cleanup;
+ }
+ free(resp);
+ return (0);
+ }
+
+ /* If we're out of labels, then not even "." has an SOA! */
+ if (*dname == '\0')
+ break;
+
+ /* Find label-terminating "."; top of loop will skip it. */
+ while (*dname != '.') {
+ if (*dname == '\\')
+ if (*++dname == '\0') {
+ errno = EMSGSIZE;
+ goto cleanup;
+ }
+ dname++;
+ }
+ }
+ DPRINTF(("get_soa: out of labels"));
+ errno = EDESTADDRREQ;
+ cleanup:
+ if (resp != NULL)
+ free(resp);
+ return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ u_char *resp;
+ ns_msg msg;
+ int n;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return (-1);
+
+ /* Go and get the NS RRs for this zone. */
+ n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+ if (n != 0) {
+ DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
+ zname, p_class(class), n));
+ free(resp);
+ return (-1);
+ }
+
+ /* Remember the NS RRs and associated A RRs that came back. */
+ if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
+ DPRINTF(("get_ns save_ns('%s', %s) failed",
+ zname, p_class(class)));
+ free(resp);
+ return (-1);
+ }
+
+ free(resp);
+ return (0);
+}
+
+static int
+get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
+ rr_ns *nsrr, *nsrr_n;
+ u_char *resp;
+
+ resp = malloc(NS_MAXMSG);
+ if (resp == NULL)
+ return(-1);
+
+ /* Go and get the A RRs for each empty NS RR on our list. */
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+ ns_msg msg;
+ int n;
+
+ nsrr_n = NEXT(nsrr, link);
+
+ if ((nsrr->flags & RR_NS_HAVE_V4) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_a,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ if ((nsrr->flags & RR_NS_HAVE_V6) == 0) {
+ n = do_query(statp, nsrr->name, class, ns_t_aaaa,
+ resp, &msg);
+ if (n < 0) {
+ DPRINTF(
+ ("get_glue: do_query('%s', %s') failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ if (n > 0) {
+ DPRINTF((
+ "get_glue: do_query('%s', %s') CNAME or DNAME found",
+ nsrr->name, p_class(class)));
+ }
+ if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+ opts, nsrr) < 0) {
+ DPRINTF(("get_glue: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ goto cleanup;
+ }
+ }
+
+ /* If it's still empty, it's just chaff. */
+ if (EMPTY(nsrr->addrs)) {
+ DPRINTF(("get_glue: removing empty '%s' NS",
+ nsrr->name));
+ free_nsrr(nsrrsp, nsrr);
+ }
+ }
+ free(resp);
+ return (0);
+
+ cleanup:
+ free(resp);
+ return (-1);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rrset_ns *nsrrsp)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ char tname[MAXDNAME];
+ const u_char *rdata;
+ rr_ns *nsrr;
+ ns_rr rr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if (ns_rr_type(rr) != ns_t_ns ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1)
+ continue;
+ nsrr = find_ns(nsrrsp, ns_rr_name(rr));
+ if (nsrr == NULL) {
+ nsrr = malloc(sizeof *nsrr);
+ if (nsrr == NULL) {
+ DPRINTF(("save_ns: malloc failed"));
+ return (-1);
+ }
+ rdata = ns_rr_rdata(rr);
+ if (ns_name_uncompress(ns_msg_base(*msg),
+ ns_msg_end(*msg), rdata,
+ tname, sizeof tname) < 0) {
+ DPRINTF(("save_ns: ns_name_uncompress failed")
+ );
+ free(nsrr);
+ return (-1);
+ }
+ nsrr->name = strdup(tname);
+ if (nsrr->name == NULL) {
+ DPRINTF(("save_ns: strdup failed"));
+ free(nsrr);
+ return (-1);
+ }
+ INIT_LINK(nsrr, link);
+ INIT_LIST(nsrr->addrs);
+ nsrr->flags = 0;
+ APPEND(*nsrrsp, nsrr, link);
+ }
+ if (save_a(statp, msg, ns_s_ar,
+ nsrr->name, class, opts, nsrr) < 0) {
+ DPRINTF(("save_ns: save_r('%s', %s) failed",
+ nsrr->name, p_class(class)));
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+ const char *owner, ns_class class, int opts,
+ rr_ns *nsrr)
+{
+ int i;
+
+ for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+ ns_rr rr;
+ rr_a *arr;
+
+ if (ns_parserr(msg, sect, i, &rr) < 0) {
+ DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+ p_section(sect, ns_o_query), i));
+ return (-1);
+ }
+ if ((ns_rr_type(rr) != ns_t_a &&
+ ns_rr_type(rr) != ns_t_aaaa) ||
+ ns_rr_class(rr) != class ||
+ ns_samename(ns_rr_name(rr), owner) != 1 ||
+ ns_rr_rdlen(rr) != NS_INADDRSZ)
+ continue;
+ if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
+ continue;
+ if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
+ continue;
+ arr = malloc(sizeof *arr);
+ if (arr == NULL) {
+ DPRINTF(("save_a: malloc failed"));
+ return (-1);
+ }
+ INIT_LINK(arr, link);
+ memset(&arr->addr, 0, sizeof(arr->addr));
+ switch (ns_rr_type(rr)) {
+ case ns_t_a:
+ arr->addr.sin.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin.sin_len = sizeof(arr->addr.sin);
+#endif
+ memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
+ NS_INADDRSZ);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V4;
+ break;
+ case ns_t_aaaa:
+ arr->addr.sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
+#endif
+ memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
+ arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
+ nsrr->flags |= RR_NS_HAVE_V6;
+ break;
+ default:
+ abort();
+ }
+ APPEND(nsrr->addrs, arr, link);
+ }
+ return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+ rr_ns *nsrr;
+
+ while ((nsrr = HEAD(*nsrrsp)) != NULL)
+ free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+ rr_a *arr;
+ char *tmp;
+
+ while ((arr = HEAD(nsrr->addrs)) != NULL) {
+ UNLINK(nsrr->addrs, arr, link);
+ free(arr);
+ }
+ DE_CONST(nsrr->name, tmp);
+ free(tmp);
+ UNLINK(*nsrrsp, nsrr, link);
+ free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+ rr_ns *nsrr;
+
+ for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
+ if (ns_samename(nsrr->name, dname) == 1)
+ return (nsrr);
+ return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+ u_char *resp, ns_msg *msg)
+{
+ u_char req[NS_PACKETSZ];
+ int i, n;
+
+ n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+ NULL, 0, NULL, req, NS_PACKETSZ);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nmkquery failed"));
+ return (-1);
+ }
+ n = res_nsend(statp, req, n, resp, NS_MAXMSG);
+ if (n < 0) {
+ DPRINTF(("do_query: res_nsend failed"));
+ return (-1);
+ }
+ if (n == 0) {
+ DPRINTF(("do_query: res_nsend returned 0"));
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ns_initparse(resp, n, msg) < 0) {
+ DPRINTF(("do_query: ns_initparse failed"));
+ return (-1);
+ }
+ n = 0;
+ for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+ ns_rr rr;
+
+ if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+ DPRINTF(("do_query: ns_parserr failed"));
+ return (-1);
+ }
+ n += (ns_rr_class(rr) == class &&
+ (ns_rr_type(rr) == ns_t_cname ||
+ ns_rr_type(rr) == ns_t_dname));
+ }
+ return (n);
+}
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_findzonecut: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_init.c b/usr/src/lib/libresolv2_joy/common/resolv/res_init.c
new file mode 100644
index 0000000000..10254d1931
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_init.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
+static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#ifndef HAVE_MD5
+# include "../dst/md5.h"
+#else
+# ifdef SOLARIS2
+# include <sys/md5.h>
+# endif
+#endif
+#ifndef _MD5_H_
+# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
+#endif
+
+
+#include "port_after.h"
+
+/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
+#include <resolv_joy.h>
+
+/* ISC purposely put port_after.h before <resolv.h> to force in6 stuff
+ * (above) so we explicitly include port_resolv.h here */
+#include "port_resolv.h"
+
+#include "res_private.h"
+
+/*% Options. Should all be left alone. */
+#define RESOLVSORT
+#define DEBUG
+
+#ifdef SUNW_INITCHKIF
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <sys/sockio.h>
+#define MAXIFS 8192
+#endif /* SUNW_INITCHKIF */
+
+#ifdef SOLARIS2
+#include <sys/systeminfo.h>
+#endif
+
+static void res_setoptions __P((res_state, const char *, const char *));
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask __P((struct in_addr));
+#endif
+
+#if !defined(isascii) /*%< XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+/*
+ * Resolver state default settings.
+ */
+
+/*%
+ * Set up default settings. If the configuration file exist, the values
+ * there will have precedence. Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+res_ninit(res_state statp) {
+ extern int __res_vinit(res_state, int);
+ return (__res_vinit(statp, 0));
+}
+
+/*% This function has to be reachable by res_data.c but not publically. */
+int
+__res_vinit(res_state statp, int preinit) {
+ register FILE *fp;
+ register char *cp, **pp;
+ register int n;
+ char buf[BUFSIZ];
+ int nserv = 0; /*%< number of nameserver records read from file */
+ int haveenv = 0;
+ int havesearch = 0;
+#ifdef RESOLVSORT
+ int nsort = 0;
+ char *net;
+#endif
+ int dots;
+ union res_sockaddr_union u[2];
+ int maxns = MAXNS;
+
+ RES_SET_H_ERRNO(statp, 0);
+ if (statp->_u._ext.ext != NULL)
+ res_ndestroy(statp);
+
+ if (!preinit) {
+ statp->retrans = RES_TIMEOUT;
+ statp->retry = RES_DFLRETRY;
+ statp->options = RES_DEFAULT;
+ res_rndinit(statp);
+ statp->id = res_nrandomid(statp);
+ }
+
+ memset(u, 0, sizeof(u));
+#ifdef USELOOPBACK
+ u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
+#endif
+ u[nserv].sin.sin_family = AF_INET;
+ u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
+#endif
+ nserv++;
+#ifdef HAS_INET6_STRUCTS
+#ifdef USELOOPBACK
+ u[nserv].sin6.sin6_addr = in6addr_loopback;
+#else
+ u[nserv].sin6.sin6_addr = in6addr_any;
+#endif
+ u[nserv].sin6.sin6_family = AF_INET6;
+ u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
+#ifdef HAVE_SA_LEN
+ u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ nserv++;
+#endif
+ statp->nscount = 0;
+ statp->ndots = 1;
+ statp->pfcode = 0;
+ statp->_vcsock = -1;
+ statp->_flags = 0;
+ statp->qhook = NULL;
+ statp->rhook = NULL;
+ statp->_u._ext.nscount = 0;
+ statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
+ if (statp->_u._ext.ext != NULL) {
+ memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
+ statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
+ strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
+ strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
+ } else {
+ /*
+ * Historically res_init() rarely, if at all, failed.
+ * Examples and applications exist which do not check
+ * our return code. Furthermore several applications
+ * simply call us to get the systems domainname. So
+ * rather then immediately fail here we store the
+ * failure, which is returned later, in h_errno. And
+ * prevent the collection of 'nameserver' information
+ * by setting maxns to 0. Thus applications that fail
+ * to check our return code wont be able to make
+ * queries anyhow.
+ */
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ maxns = 0;
+ }
+#ifdef RESOLVSORT
+ statp->nsort = 0;
+#endif
+ res_setservers(statp, u, nserv);
+
+#ifdef SUNW_INITCHKIF
+/*
+ * Short circuit res_init() if no non-loopback interfaces are up. This is
+ * done to avoid boot delays if "dns" comes before "files" in nsswitch.conf.
+ * An additional fix has been added to this code, to count all external
+ * interfaces, which includes the IPv6 interfaces. If no external interfaces
+ * are found, an additional check is carried out to determine if any deprecated
+ * interfaces are up.
+ */
+ {
+ int s;
+ struct lifnum lifn;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("res_init: socket");
+ goto freedata;
+ }
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_EXTERNAL_SOURCE;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
+ close(s);
+ goto freedata;
+ }
+ if (lifn.lifn_count == 0) {
+ /*
+ * Check if there are any deprecated interfaces up
+ */
+ struct lifconf lifc;
+ uchar_t *buf;
+ int buflen, i, int_up = 0;
+
+ lifn.lifn_flags = 0;
+ if ((ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) ||
+ (lifn.lifn_count < 1)) {
+ close(s);
+ goto freedata;
+ }
+
+ buflen = lifn.lifn_count * sizeof (struct lifreq);
+ buf = (uchar_t *)malloc(buflen);
+ if (buf == NULL) {
+ close(s);
+ goto freedata;
+ }
+
+ lifc.lifc_family = AF_UNSPEC;
+ lifc.lifc_flags = 0;
+ lifc.lifc_len = buflen;
+ lifc.lifc_lifcu.lifcu_buf = (caddr_t)buf;
+ if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
+ close(s);
+ free(buf);
+ goto freedata;
+ }
+
+ for (i = 0; i < lifn.lifn_count; ++i) {
+ struct lifreq *lreqp, lreq;
+
+ lreqp = (struct lifreq *)&lifc.lifc_req[i];
+ strlcpy(lreq.lifr_name, lreqp->lifr_name,
+ sizeof (lreq.lifr_name));
+ if (ioctl(s, SIOCGLIFFLAGS, &lreq) < 0) {
+ close(s);
+ free(buf);
+ goto freedata;
+ }
+ if ((lreq.lifr_flags & IFF_UP) &&
+ !(lreq.lifr_flags & IFF_NOLOCAL) &&
+ !(lreq.lifr_flags & IFF_NOXMIT) &&
+ !(lreq.lifr_flags & IFF_LOOPBACK)) {
+ int_up = 1;
+ break;
+ }
+ }
+ free(buf);
+
+ if (!int_up) {
+ close(s);
+ goto freedata;
+ }
+ }
+ close(s);
+ }
+#endif /* SUNW_INITCHKIF */
+
+#ifdef SOLARIS2
+ /*
+ * The old libresolv derived the defaultdomain from NIS/NIS+.
+ * We want to keep this behaviour
+ */
+ {
+ char buf[sizeof(statp->defdname)], *cp;
+ int ret;
+
+ if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
+ (unsigned int)ret <= sizeof(buf)) {
+ if (buf[0] == '+')
+ buf[0] = '.';
+ cp = strchr(buf, '.');
+ cp = (cp == NULL) ? buf : (cp + 1);
+ strncpy(statp->defdname, cp,
+ sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ }
+ }
+#endif /* SOLARIS2 */
+
+ /* Allow user to override the local domain definition */
+ if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+ (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ haveenv++;
+
+ /*
+ * Set search list to be blank-separated strings
+ * from rest of env value. Permits users of LOCALDOMAIN
+ * to still have a search list, and anyone to set the
+ * one that they want to use as an individual (even more
+ * important now that the rfc1535 stuff restricts searches)
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == '\n') /*%< silly backwards compat */
+ break;
+ else if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ havesearch = 1;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ }
+
+#define MATCH(line, name) \
+ (!strncmp(line, name, sizeof(name) - 1) && \
+ (line[sizeof(name) - 1] == ' ' || \
+ line[sizeof(name) - 1] == '\t'))
+
+ nserv = 0;
+ if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* skip comments */
+ if (*buf == ';' || *buf == '#')
+ continue;
+ /* read default domain name */
+ if (MATCH(buf, "domain")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
+ *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+ /* set search list */
+ if (MATCH(buf, "search")) {
+ if (haveenv) /*%< skip if have from environ */
+ continue;
+ cp = buf + sizeof("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+ statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+ if ((cp = strchr(statp->defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = statp->defdname;
+ pp = statp->dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ havesearch = 1;
+ continue;
+ }
+ /* read nameservers to query */
+ if (MATCH(buf, "nameserver") && nserv < maxns) {
+ struct addrinfo hints, *ai;
+ char sbuf[NI_MAXSERV];
+ const size_t minsiz =
+ sizeof(statp->_u._ext.ext->nsaddrs[0]);
+
+ cp = buf + sizeof("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ cp[strcspn(cp, ";# \t\n")] = '\0';
+ if ((*cp != '\0') && (*cp != '\n')) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ sprintf(sbuf, "%u", NAMESERVER_PORT);
+ if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
+ ai->ai_addrlen <= minsiz) {
+ if (statp->_u._ext.ext != NULL) {
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ }
+ if (ai->ai_addrlen <=
+ sizeof(statp->nsaddr_list[nserv])) {
+ memcpy(&statp->nsaddr_list[nserv],
+ ai->ai_addr, ai->ai_addrlen);
+ } else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ freeaddrinfo(ai);
+ nserv++;
+ }
+ }
+ continue;
+ }
+#ifdef RESOLVSORT
+ if (MATCH(buf, "sortlist")) {
+ struct in_addr a;
+
+ cp = buf + sizeof("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0' || *cp == '\n' || *cp == ';')
+ break;
+ net = cp;
+ while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+ isascii(*cp) && !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].addr = a;
+ if (ISSORTMASK(n)) {
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) &&
+ !isspace((unsigned char)*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inet_aton(net, &a)) {
+ statp->sort_list[nsort].mask = a.s_addr;
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ } else {
+ statp->sort_list[nsort].mask =
+ net_mask(statp->sort_list[nsort].addr);
+ }
+ nsort++;
+ }
+ *cp = n;
+ }
+ continue;
+ }
+#endif
+ if (MATCH(buf, "options")) {
+ res_setoptions(statp, buf + sizeof("options") - 1, "conf");
+ continue;
+ }
+ }
+ if (nserv > 0)
+ statp->nscount = nserv;
+#ifdef RESOLVSORT
+ statp->nsort = nsort;
+#endif
+ (void) fclose(fp);
+ }
+/*
+ * Last chance to get a nameserver. This should not normally
+ * be necessary
+ */
+#ifdef NO_RESOLV_CONF
+ if(nserv == 0)
+ nserv = get_nameservers(statp);
+#endif
+
+ if (statp->defdname[0] == 0 &&
+ gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
+ (cp = strchr(buf, '.')) != NULL)
+ strcpy(statp->defdname, cp + 1);
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0) {
+ pp = statp->dnsrch;
+ *pp++ = statp->defdname;
+ *pp = NULL;
+
+ dots = 0;
+ for (cp = statp->defdname; *cp; cp++)
+ dots += (*cp == '.');
+
+ cp = statp->defdname;
+ while (pp < statp->dnsrch + MAXDFLSRCH) {
+ if (dots < LOCALDOMAINPARTS)
+ break;
+ cp = strchr(cp, '.') + 1; /*%< we know there is one */
+ *pp++ = cp;
+ dots--;
+ }
+ *pp = NULL;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG) {
+ printf(";; res_init()... default dnsrch list:\n");
+ for (pp = statp->dnsrch; *pp; pp++)
+ printf(";;\t%s\n", *pp);
+ printf(";;\t..END..\n");
+ }
+#endif
+ }
+
+ if ((cp = getenv("RES_OPTIONS")) != NULL)
+ res_setoptions(statp, cp, "env");
+ statp->options |= RES_INIT;
+ return (statp->res_h_errno);
+#ifdef SUNW_INITCHKIF
+freedata:
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ if (statp->_u._ext.ext != NULL) {
+ free(statp->_u._ext.ext);
+ statp->_u._ext.ext = NULL;
+ }
+ return (-1);
+#endif /* SUNW_INITCHKIF */
+
+}
+
+static void
+res_setoptions(res_state statp, const char *options, const char *source)
+{
+ const char *cp = options;
+ int i;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_setoptions(\"%s\", \"%s\")...\n",
+ options, source);
+#endif
+ while (*cp) {
+ /* skip leading and inner runs of spaces */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* search for and process individual options */
+ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+ i = atoi(cp + sizeof("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ statp->ndots = i;
+ else
+ statp->ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tndots=%d\n", statp->ndots);
+#endif
+ } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
+ i = atoi(cp + sizeof("timeout:") - 1);
+ if (i <= RES_MAXRETRANS)
+ statp->retrans = i;
+ else
+ statp->retrans = RES_MAXRETRANS;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\ttimeout=%d\n", statp->retrans);
+#endif
+#ifdef SOLARIS2
+ } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
+ /*
+ * For backward compatibility, 'retrans' is
+ * supported as an alias for 'timeout', though
+ * without an imposed maximum.
+ */
+ statp->retrans = atoi(cp + sizeof("retrans:") - 1);
+ } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
+ /*
+ * For backward compatibility, 'retry' is
+ * supported as an alias for 'attempts', though
+ * without an imposed maximum.
+ */
+ statp->retry = atoi(cp + sizeof("retry:") - 1);
+#endif /* SOLARIS2 */
+ } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
+ i = atoi(cp + sizeof("attempts:") - 1);
+ if (i <= RES_MAXRETRY)
+ statp->retry = i;
+ else
+ statp->retry = RES_MAXRETRY;
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";;\tattempts=%d\n", statp->retry);
+#endif
+ } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+ if (!(statp->options & RES_DEBUG)) {
+ printf(";; res_setoptions(\"%s\", \"%s\")..\n",
+ options, source);
+ statp->options |= RES_DEBUG;
+ }
+ printf(";;\tdebug\n");
+#endif
+ } else if (!strncmp(cp, "no_tld_query",
+ sizeof("no_tld_query") - 1) ||
+ !strncmp(cp, "no-tld-query",
+ sizeof("no-tld-query") - 1)) {
+ statp->options |= RES_NOTLDQUERY;
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ statp->options |= RES_USE_INET6;
+ } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
+ statp->options |= RES_ROTATE;
+ } else if (!strncmp(cp, "no-check-names",
+ sizeof("no-check-names") - 1)) {
+ statp->options |= RES_NOCHECKNAME;
+ }
+#ifdef RES_USE_EDNS0
+ else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+ statp->options |= RES_USE_EDNS0;
+ }
+#endif
+ else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
+ statp->options |= RES_USE_DNAME;
+ }
+ else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
+ strncpy(ext->nsuffix, cp, i);
+ ext->nsuffix[i] = '\0';
+ }
+ else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
+ if (ext == NULL)
+ goto skip;
+ cp += sizeof("nibble2:") - 1;
+ i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
+ strncpy(ext->nsuffix2, cp, i);
+ ext->nsuffix2[i] = '\0';
+ }
+ else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
+ cp += sizeof("v6revmode:") - 1;
+ /* "nibble" and "bitstring" used to be valid */
+ if (!strncmp(cp, "single", sizeof("single") - 1)) {
+ statp->options |= RES_NO_NIBBLE2;
+ } else if (!strncmp(cp, "both", sizeof("both") - 1)) {
+ statp->options &=
+ ~RES_NO_NIBBLE2;
+ }
+ }
+ else {
+ /* XXX - print a warning here? */
+ }
+ skip:
+ /* skip to next run of spaces */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(in) /*!< XXX - should really use system's version of this */
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+void
+res_rndinit(res_state statp)
+{
+ struct timeval now;
+ u_int32_t u32;
+ u_int16_t u16;
+
+ gettimeofday(&now, NULL);
+ u32 = now.tv_sec;
+ memcpy(statp->_u._ext._rnd, &u32, 4);
+ u32 = now.tv_usec;
+ memcpy(statp->_u._ext._rnd + 4, &u32, 4);
+ u32 += now.tv_sec;
+ memcpy(statp->_u._ext._rnd + 8, &u32, 4);
+ u16 = getpid();
+ memcpy(statp->_u._ext._rnd + 12, &u16, 2);
+
+}
+
+u_int
+res_nrandomid(res_state statp) {
+ struct timeval now;
+ u_int16_t u16;
+ MD5_CTX ctx;
+
+ gettimeofday(&now, NULL);
+ u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
+
+ memcpy(statp->_u._ext._rnd + 14, &u16, 2);
+#ifndef HAVE_MD5
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, statp->_u._ext._rnd, 16);
+ MD5_Final(statp->_u._ext._rnd, &ctx);
+#else
+ MD5Init(&ctx);
+ MD5Update(&ctx, statp->_u._ext._rnd, 16);
+ MD5Final(statp->_u._ext._rnd, &ctx);
+#endif
+ memcpy(&u16, statp->_u._ext._rnd + 14, 2);
+ return ((u_int) u16);
+}
+
+/*%
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+void
+res_nclose(res_state statp) {
+ int ns;
+
+ if (statp->_vcsock >= 0) {
+ (void) close(statp->_vcsock);
+ statp->_vcsock = -1;
+ statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+ }
+ for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
+ if (statp->_u._ext.nssocks[ns] != -1) {
+ (void) close(statp->_u._ext.nssocks[ns]);
+ statp->_u._ext.nssocks[ns] = -1;
+ }
+ }
+}
+
+void
+res_ndestroy(res_state statp) {
+ res_nclose(statp);
+ if (statp->_u._ext.ext != NULL)
+ free(statp->_u._ext.ext);
+ statp->options &= ~RES_INIT;
+ statp->_u._ext.ext = NULL;
+}
+
+const char *
+res_get_nibblesuffix(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix);
+ return ("ip6.arpa");
+}
+
+const char *
+res_get_nibblesuffix2(res_state statp) {
+ if (statp->_u._ext.ext)
+ return (statp->_u._ext.ext->nsuffix2);
+ return ("ip6.int");
+}
+
+void
+res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
+ int i, nserv;
+ size_t size;
+
+ /* close open servers */
+ res_nclose(statp);
+
+ /* cause rtt times to be forgotten */
+ statp->_u._ext.nscount = 0;
+
+ nserv = 0;
+ for (i = 0; i < cnt && nserv < MAXNS; i++) {
+ switch (set->sin.sin_family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+ &set->sin6, size);
+ if (size <= sizeof(statp->nsaddr_list[nserv]))
+ memcpy(&statp->nsaddr_list[nserv],
+ &set->sin6, size);
+ else
+ statp->nsaddr_list[nserv].sin_family = 0;
+ nserv++;
+ break;
+#endif
+
+ default:
+ break;
+ }
+ set++;
+ }
+ statp->nscount = nserv;
+
+}
+
+int
+res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
+ int i;
+ size_t size;
+ u_int16_t family;
+
+ for (i = 0; i < statp->nscount && i < cnt; i++) {
+ if (statp->_u._ext.ext)
+ family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
+ else
+ family = statp->nsaddr_list[i].sin_family;
+
+ switch (family) {
+ case AF_INET:
+ size = sizeof(set->sin);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin, &statp->nsaddr_list[i],
+ size);
+ break;
+
+#ifdef HAS_INET6_STRUCTS
+ case AF_INET6:
+ size = sizeof(set->sin6);
+ if (statp->_u._ext.ext)
+ memcpy(&set->sin6,
+ &statp->_u._ext.ext->nsaddrs[i],
+ size);
+ else
+ memcpy(&set->sin6, &statp->nsaddr_list[i],
+ size);
+ break;
+#endif
+
+ default:
+ set->sin.sin_family = 0;
+ break;
+ }
+ set++;
+ }
+ return (statp->nscount);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_mkquery.c b/usr/src/lib/libresolv2_joy/common/resolv/res_mkquery.c
new file mode 100644
index 0000000000..cf36855e9d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_mkquery.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#ifdef SUNW_CONFCHECK
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/stat.h>
+#endif /* SUNW_CONFCHECK */
+
+
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+
+extern const char *_res_opcodes[];
+
+#ifdef SUNW_CONFCHECK
+static int _confcheck(res_state statp);
+#endif /* SUNW_CONFCHECK */
+
+
+/*%
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+ int op, /*!< opcode of query */
+ const char *dname, /*!< domain name */
+ int class, int type, /*!< class and type of query */
+ const u_char *data, /*!< resource record data */
+ int datalen, /*!< length of data */
+ const u_char *newrr_in, /*!< new rr for modify or append */
+ u_char *buf, /*!< buffer to put query */
+ int buflen) /*!< size of buffer */
+{
+ register HEADER *hp;
+ register u_char *cp, *ep;
+ register int n;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+
+ UNUSED(newrr_in);
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nmkquery(%s, %s, %s, %s)\n",
+ _res_opcodes[op], dname, p_class(class), p_type(type));
+#endif
+
+#ifdef SUNW_CONFCHECK
+ /*
+ * 1247019, 1265838, and 4034368: Check to see if we can
+ * bailout quickly.
+ */
+ if (_confcheck(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return(-1);
+ }
+#endif /* SUNW_CONFCHECK */
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0U;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ ep = buf + buflen;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY: /*FALLTHROUGH*/
+ case NS_NOTIFY_OP:
+ if (ep - cp < QFIXEDSZ)
+ return (-1);
+ if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ if ((ep - cp) < RRFIXEDSZ)
+ return (-1);
+ n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ns_put16(T_NULL, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(0, cp);
+ cp += INT16SZ;
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (ep - cp < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /*%< no domain name */
+ ns_put16(type, cp);
+ cp += INT16SZ;
+ ns_put16(class, cp);
+ cp += INT16SZ;
+ ns_put32(0, cp);
+ cp += INT32SZ;
+ ns_put16(datalen, cp);
+ cp += INT16SZ;
+ if (datalen) {
+ memcpy(cp, data, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return (-1);
+ }
+ return (cp - buf);
+}
+
+#ifdef RES_USE_EDNS0
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+
+int
+res_nopt(res_state statp,
+ int n0, /*%< current offset in buffer */
+ u_char *buf, /*%< buffer to put query */
+ int buflen, /*%< size of buffer */
+ int anslen) /*%< UDP answer buffer size */
+{
+ register HEADER *hp;
+ register u_char *cp, *ep;
+ u_int16_t flags = 0;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0U)
+ printf(";; res_nopt()\n");
+#endif
+
+ hp = (HEADER *) buf;
+ cp = buf + n0;
+ ep = buf + buflen;
+
+ if ((ep - cp) < 1 + RRFIXEDSZ)
+ return (-1);
+
+ *cp++ = 0; /*%< "." */
+ ns_put16(ns_t_opt, cp); /*%< TYPE */
+ cp += INT16SZ;
+ ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */
+ cp += INT16SZ;
+ *cp++ = NOERROR; /*%< extended RCODE */
+ *cp++ = 0; /*%< EDNS version */
+
+ if (statp->options & RES_USE_DNSSEC) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_opt()... ENDS0 DNSSEC\n");
+#endif
+ flags |= NS_OPT_DNSSEC_OK;
+ }
+ ns_put16(flags, cp);
+ cp += INT16SZ;
+
+ ns_put16(0U, cp); /*%< RDLEN */
+ cp += INT16SZ;
+
+ hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+ return (cp - buf);
+}
+
+/*
+ * Construct variable data (RDATA) block for OPT psuedo-RR, append it
+ * to the buffer, then update the RDLEN field (previously set to zero by
+ * res_nopt()) with the new RDATA length.
+ */
+int
+res_nopt_rdata(res_state statp,
+ int n0, /*%< current offset in buffer */
+ u_char *buf, /*%< buffer to put query */
+ int buflen, /*%< size of buffer */
+ u_char *rdata, /*%< ptr to start of opt rdata */
+ u_short code, /*%< OPTION-CODE */
+ u_short len, /*%< OPTION-LENGTH */
+ u_char *data) /*%< OPTION_DATA */
+{
+ register u_char *cp, *ep;
+
+#ifdef DEBUG
+ if ((statp->options & RES_DEBUG) != 0U)
+ printf(";; res_nopt_rdata()\n");
+#endif
+
+ cp = buf + n0;
+ ep = buf + buflen;
+
+ if ((ep - cp) < (4 + len))
+ return (-1);
+
+ if (rdata < (buf + 2) || rdata >= ep)
+ return (-1);
+
+ ns_put16(code, cp);
+ cp += INT16SZ;
+
+ ns_put16(len, cp);
+ cp += INT16SZ;
+
+ memcpy(cp, data, len);
+ cp += len;
+
+ len = cp - rdata;
+ ns_put16(len, rdata - 2); /* Update RDLEN field */
+
+ return (cp - buf);
+}
+#endif
+
+#ifdef SUNW_CONFCHECK
+
+/*
+ * Time out quickly if there is no /etc/resolv.conf and a TCP connection
+ * to the local DNS server fails.
+ */
+static int _confcheck(res_state statp)
+{
+ int ns;
+ struct stat rc_stat;
+ struct sockaddr_in ns_sin;
+
+ /* First, we check to see if /etc/resolv.conf exists.
+ * If it doesn't, then it is likely that the localhost is
+ * the nameserver.
+ */
+ if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
+
+ /* Next, we check to see if _res.nsaddr is set to loopback.
+ * If it isn't, it has been altered by the application
+ * explicitly and we then want to bail with success.
+ */
+ if (statp->nsaddr.sin_addr.S_un.S_addr ==
+ htonl(INADDR_LOOPBACK)) {
+
+ /* Lastly, we try to connect to the TCP port of the
+ * nameserver. If this fails, then we know that
+ * DNS is misconfigured and we can quickly exit.
+ */
+ ns = socket(AF_INET, SOCK_STREAM, 0);
+ IN_SET_LOOPBACK_ADDR(&ns_sin);
+ ns_sin.sin_port = htons(NAMESERVER_PORT);
+ if (connect(ns, (struct sockaddr *) &ns_sin,
+ sizeof ns_sin) == -1) {
+ close(ns);
+ return(-1);
+ }
+ else {
+ close(ns);
+
+ return(0);
+ }
+ }
+
+ return(0);
+ }
+
+ return (0);
+}
+#endif /* SUNW_CONFCHECK */
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.c b/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.c
new file mode 100644
index 0000000000..8f73e281d0
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.c
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+int res_protocolnumber(const char *);
+int res_servicenumber(const char *);
+
+/*%
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ *
+ * On error,
+ * returns
+ *\li -1 if error in reading a word/number in rdata
+ * portion for update packets
+ *\li -2 if length of buffer passed is insufficient
+ *\li -3 if zone section is not the first section in
+ * the linked list, or section order has a problem
+ *\li -4 on a number overflow
+ *\li -5 unknown operation or no records
+ */
+int
+res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
+ ns_updrec *rrecp_start = rrecp_in;
+ HEADER *hp;
+ u_char *cp, *sp2, *startp, *endp;
+ int n, i, soanum, multiline;
+ ns_updrec *rrecp;
+ struct in_addr ina;
+ struct in6_addr in6a;
+ char buf2[MAXDNAME];
+ u_char buf3[MAXDNAME];
+ int section, numrrs = 0, counts[ns_s_max];
+ u_int16_t rtype, rclass;
+ u_int32_t n1, rttl;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+ int siglen, keylen, certlen;
+
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
+ hp->opcode = ns_o_update;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ buflen -= HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ if (rrecp_start == NULL)
+ return (-5);
+ else if (rrecp_start->r_section != S_ZONE)
+ return (-3);
+
+ memset(counts, 0, sizeof counts);
+ for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
+ numrrs++;
+ section = rrecp->r_section;
+ if (section < 0 || section >= ns_s_max)
+ return (-1);
+ counts[section]++;
+ for (i = section + 1; i < ns_s_max; i++)
+ if (counts[i])
+ return (-3);
+ rtype = rrecp->r_type;
+ rclass = rrecp->r_class;
+ rttl = rrecp->r_ttl;
+ /* overload class and type */
+ if (section == S_PREREQ) {
+ rttl = 0;
+ switch (rrecp->r_opcode) {
+ case YXDOMAIN:
+ rclass = C_ANY;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXDOMAIN:
+ rclass = C_NONE;
+ rtype = T_ANY;
+ rrecp->r_size = 0;
+ break;
+ case NXRRSET:
+ rclass = C_NONE;
+ rrecp->r_size = 0;
+ break;
+ case YXRRSET:
+ if (rrecp->r_size == 0)
+ rclass = C_ANY;
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ } else if (section == S_UPDATE) {
+ switch (rrecp->r_opcode) {
+ case DELETE:
+ rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
+ break;
+ case ADD:
+ break;
+ default:
+ fprintf(stderr,
+ "res_mkupdate: incorrect opcode: %d\n",
+ rrecp->r_opcode);
+ fflush(stderr);
+ return (-1);
+ }
+ }
+
+ /*
+ * XXX appending default domain to owner name is omitted,
+ * fqdn must be provided
+ */
+ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
+ lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n + 2*INT16SZ);
+ PUTSHORT(rtype, cp);
+ PUTSHORT(rclass, cp);
+ if (section == S_ZONE) {
+ if (numrrs != 1 || rrecp->r_type != T_SOA)
+ return (-3);
+ continue;
+ }
+ ShrinkBuffer(INT32SZ + INT16SZ);
+ PUTLONG(rttl, cp);
+ sp2 = cp; /*%< save pointer to length byte */
+ cp += INT16SZ;
+ if (rrecp->r_size == 0) {
+ if (section == S_UPDATE && rclass != C_ANY)
+ return (-1);
+ else {
+ PUTSHORT(0, sp2);
+ continue;
+ }
+ }
+ startp = rrecp->r_data;
+ endp = startp + rrecp->r_size - 1;
+ /* XXX this should be done centrally. */
+ switch (rrecp->r_type) {
+ case T_A:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ case ns_t_dname:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ if (rrecp->r_type == T_SOA) {
+ ShrinkBuffer(5 * INT32SZ);
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp == '(') {
+ multiline = 1;
+ startp++;
+ } else
+ multiline = 0;
+ /* serial, refresh, retry, expire, minimum */
+ for (i = 0; i < 5; i++) {
+ soanum = getnum_str(&startp, endp);
+ if (soanum < 0)
+ return (-1);
+ PUTLONG(soanum, cp);
+ }
+ if (multiline) {
+ while (isspace(*startp) || !*startp)
+ startp++;
+ if (*startp != ')')
+ return (-1);
+ }
+ }
+ break;
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_SRV:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ case T_PX:
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT(n, cp);
+ ShrinkBuffer(INT16SZ);
+ for (i = 0; i < 2; i++) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs,
+ lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ }
+ break;
+ case T_WKS: {
+ char bm[MAXPORT/8];
+ unsigned int maxbm = 0;
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (!inet_aton(buf2, &ina))
+ return (-1);
+ n1 = ntohl(ina.s_addr);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(n1, cp);
+
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if ((i = res_protocolnumber(buf2)) < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = i & 0xff;
+
+ for (i = 0; i < MAXPORT/8 ; i++)
+ bm[i] = 0;
+
+ while (getword_str(buf2, sizeof buf2, &startp, endp)) {
+ if ((n = res_servicenumber(buf2)) <= 0)
+ return (-1);
+
+ if (n < MAXPORT) {
+ bm[n/8] |= (0x80>>(n%8));
+ if ((unsigned)n > maxbm)
+ maxbm = n;
+ } else
+ return (-1);
+ }
+ maxbm = maxbm/8 + 1;
+ ShrinkBuffer(maxbm);
+ memcpy(cp, bm, maxbm);
+ cp += maxbm;
+ break;
+ }
+ case T_HINFO:
+ for (i = 0; i < 2; i++) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_TXT:
+ for (;;) {
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ if (cp != (sp2 + INT16SZ))
+ break;
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ }
+ break;
+ case T_X25:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_ISDN:
+ /* RFC1183 */
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ return (-1);
+ if ((n > 255) || (n == 0))
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ if ((n = getstr_str(buf2, sizeof buf2, &startp,
+ endp)) < 0)
+ n = 0;
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ break;
+ case T_NSAP:
+ if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else {
+ return (-1);
+ }
+ break;
+ case T_LOC:
+ if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
+ ShrinkBuffer(n);
+ memcpy(cp, buf2, n);
+ cp += n;
+ } else
+ return (-1);
+ break;
+ case ns_t_sig:
+ {
+ int sig_type, success, dateerror;
+ u_int32_t exptime, timesigned;
+
+ /* type */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ sig_type = sym_ston(__p_type_syms, buf2, &success);
+ if (!success || sig_type == ns_t_any)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(sig_type, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* labels */
+ n = getnum_str(&startp, endp);
+ if (n <= 0 || n > 255)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* ottl & expire */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(rttl, cp);
+ }
+ else {
+ char *ulendp;
+ u_int32_t ottl;
+
+ errno = 0;
+ ottl = strtoul(buf2, &ulendp, 10);
+ if (errno != 0 ||
+ (ulendp != NULL && *ulendp != '\0'))
+ return (-1);
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(ottl, cp);
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ return (-1);
+ exptime = ns_datetosecs(buf2, &dateerror);
+ if (dateerror)
+ return (-1);
+ }
+ /* expire */
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(exptime, cp);
+ /* timesigned */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ timesigned = ns_datetosecs(buf2, &dateerror);
+ if (!dateerror) {
+ ShrinkBuffer(INT32SZ);
+ PUTLONG(timesigned, cp);
+ }
+ else
+ return (-1);
+ /* footprint */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* signer name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ /* sig */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ siglen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (siglen < 0)
+ return (-1);
+ ShrinkBuffer(siglen);
+ memcpy(cp, buf3, siglen);
+ cp += siglen;
+ break;
+ }
+ case ns_t_key:
+ /* flags */
+ n = gethexnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* proto */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* key */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ keylen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (keylen < 0)
+ return (-1);
+ ShrinkBuffer(keylen);
+ memcpy(cp, buf3, keylen);
+ cp += keylen;
+ break;
+ case ns_t_nxt:
+ {
+ int success, nxt_type;
+ u_char data[32];
+ int maxtype;
+
+ /* next name */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ maxtype = 0;
+ memset(data, 0, sizeof data);
+ for (;;) {
+ if (!getword_str(buf2, sizeof buf2, &startp,
+ endp))
+ break;
+ nxt_type = sym_ston(__p_type_syms, buf2,
+ &success);
+ if (!success || !ns_t_rr_p(nxt_type))
+ return (-1);
+ NS_NXT_BIT_SET(nxt_type, data);
+ if (nxt_type > maxtype)
+ maxtype = nxt_type;
+ }
+ n = maxtype/NS_NXT_BITS+1;
+ ShrinkBuffer(n);
+ memcpy(cp, data, n);
+ cp += n;
+ break;
+ }
+ case ns_t_cert:
+ /* type */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* key tag */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* alg */
+ n = getnum_str(&startp, endp);
+ if (n < 0)
+ return (-1);
+ ShrinkBuffer(1);
+ *cp++ = n;
+ /* cert */
+ if ((n = getword_str(buf2, sizeof buf2,
+ &startp, endp)) < 0)
+ return (-1);
+ certlen = b64_pton(buf2, buf3, sizeof(buf3));
+ if (certlen < 0)
+ return (-1);
+ ShrinkBuffer(certlen);
+ memcpy(cp, buf3, certlen);
+ cp += certlen;
+ break;
+ case ns_t_aaaa:
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
+ return (-1);
+ ShrinkBuffer(NS_IN6ADDRSZ);
+ memcpy(cp, &in6a, NS_IN6ADDRSZ);
+ cp += NS_IN6ADDRSZ;
+ break;
+ case ns_t_naptr:
+ /* Order Preference Flags Service Replacement Regexp */
+ /* Order */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Preference */
+ n = getnum_str(&startp, endp);
+ if (n < 0 || n > 65535)
+ return (-1);
+ ShrinkBuffer(INT16SZ);
+ PUTSHORT(n, cp);
+ /* Flags */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Service Classes */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Pattern */
+ if ((n = getstr_str(buf2, sizeof buf2,
+ &startp, endp)) < 0) {
+ return (-1);
+ }
+ if (n > 255)
+ return (-1);
+ ShrinkBuffer(n+1);
+ *cp++ = n;
+ memcpy(cp, buf2, n);
+ cp += n;
+ /* Replacement */
+ if (!getword_str(buf2, sizeof buf2, &startp, endp))
+ return (-1);
+ n = dn_comp(buf2, cp, buflen, NULL, NULL);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ ShrinkBuffer(n);
+ break;
+ default:
+ return (-1);
+ } /*switch*/
+ n = (u_int16_t)((cp - sp2) - INT16SZ);
+ PUTSHORT(n, sp2);
+ } /*for*/
+
+ hp->qdcount = htons(counts[0]);
+ hp->ancount = htons(counts[1]);
+ hp->nscount = htons(counts[2]);
+ hp->arcount = htons(counts[3]);
+ return (cp - buf);
+}
+
+/*%
+ * Get a whitespace delimited word from a string (not file)
+ * into buf. modify the start pointer to point after the
+ * word in the string.
+ */
+static int
+getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c;
+
+ for (cp = buf; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (cp != buf) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ (*startpp)++;
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (u_char)c;
+ }
+ *cp = '\0';
+ return (cp != buf);
+}
+
+/*%
+ * get a white spae delimited string from memory. Process quoted strings
+ * and \\DDD escapes. Return length or -1 on error. Returned string may
+ * contain nulls.
+ */
+static char digits[] = "0123456789";
+static int
+getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
+ char *cp;
+ int c, c1 = 0;
+ int inquote = 0;
+ int seen_quote = 0;
+ int escape = 0;
+ int dig = 0;
+
+ for (cp = buf; *startpp <= endp; ) {
+ if ((c = **startpp) == '\0')
+ break;
+ /* leading white space */
+ if ((cp == buf) && !seen_quote && isspace(c)) {
+ (*startpp)++;
+ continue;
+ }
+
+ switch (c) {
+ case '\\':
+ if (!escape) {
+ escape = 1;
+ dig = 0;
+ c1 = 0;
+ (*startpp)++;
+ continue;
+ }
+ goto do_escape;
+ case '"':
+ if (!escape) {
+ inquote = !inquote;
+ seen_quote = 1;
+ (*startpp)++;
+ continue;
+ }
+ /* fall through */
+ default:
+ do_escape:
+ if (escape) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c1 = c1 * 10 +
+ (strchr(digits, c) - digits);
+
+ if (++dig == 3) {
+ c = c1 &0xff;
+ break;
+ }
+ (*startpp)++;
+ continue;
+ }
+ escape = 0;
+ } else if (!inquote && isspace(c))
+ goto done;
+ if (cp >= buf+size-1)
+ goto done;
+ *cp++ = (u_char)c;
+ (*startpp)++;
+ }
+ }
+ done:
+ *cp = '\0';
+ return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
+}
+
+/*%
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+gethexnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
+ return getnum_str(startpp, endp);
+ (*startpp)+=2;
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isxdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ if (isdigit(c))
+ n = n * 16 + (c - '0');
+ else
+ n = n * 16 + (tolower(c) - 'a' + 10);
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Get a whitespace delimited base 10 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+getnum_str(u_char **startpp, u_char *endp) {
+ int c, n;
+ int seendigit = 0;
+ int m = 0;
+
+ for (n = 0; *startpp <= endp; ) {
+ c = **startpp;
+ if (isspace(c) || c == '\0') {
+ if (seendigit) /*%< trailing whitespace */
+ break;
+ else { /*%< leading whitespace */
+ (*startpp)++;
+ continue;
+ }
+ }
+ if (c == ';') {
+ while ((*startpp <= endp) &&
+ ((c = **startpp) != '\n'))
+ (*startpp)++;
+ if (seendigit)
+ break;
+ continue;
+ }
+ if (!isdigit(c)) {
+ if (c == ')' && seendigit) {
+ (*startpp)--;
+ break;
+ }
+ return (-1);
+ }
+ (*startpp)++;
+ n = n * 10 + (c - '0');
+ seendigit = 1;
+ }
+ return (n + m);
+}
+
+/*%
+ * Allocate a resource record buffer & save rr info.
+ */
+ns_updrec *
+res_mkupdrec(int section, const char *dname,
+ u_int class, u_int type, u_long ttl) {
+ ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
+
+ if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
+ if (rrecp)
+ free((char *)rrecp);
+ return (NULL);
+ }
+ INIT_LINK(rrecp, r_link);
+ INIT_LINK(rrecp, r_glink);
+ rrecp->r_class = (ns_class)class;
+ rrecp->r_type = (ns_type)type;
+ rrecp->r_ttl = ttl;
+ rrecp->r_section = (ns_sect)section;
+ return (rrecp);
+}
+
+/*%
+ * Free a resource record buffer created by res_mkupdrec.
+ */
+void
+res_freeupdrec(ns_updrec *rrecp) {
+ /* Note: freeing r_dp is the caller's responsibility. */
+ if (rrecp->r_dname != NULL)
+ free(rrecp->r_dname);
+ free(rrecp);
+}
+
+struct valuelist {
+ struct valuelist * next;
+ struct valuelist * prev;
+ char * name;
+ char * proto;
+ int port;
+};
+static struct valuelist *servicelist, *protolist;
+
+static void
+res_buildservicelist() {
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ while ((sp = getservent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(sp->s_name);
+ slp->proto = strdup(sp->s_proto);
+ if ((slp->name == NULL) || (slp->proto == NULL)) {
+ if (slp->name) free(slp->name);
+ if (slp->proto) free(slp->proto);
+ free(slp);
+ break;
+ }
+ slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+void
+res_destroyservicelist() {
+ struct valuelist *slp, *slp_next;
+
+ for (slp = servicelist; slp != NULL; slp = slp_next) {
+ slp_next = slp->next;
+ free(slp->name);
+ free(slp->proto);
+ free(slp);
+ }
+ servicelist = (struct valuelist *)0;
+}
+
+void
+res_buildprotolist(void) {
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ while ((pp = getprotoent()) != NULL) {
+ slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+ if (!slp)
+ break;
+ slp->name = strdup(pp->p_name);
+ if (slp->name == NULL) {
+ free(slp);
+ break;
+ }
+ slp->port = pp->p_proto; /*%< host byte order */
+ slp->next = protolist;
+ slp->prev = NULL;
+ if (protolist)
+ protolist->prev = slp;
+ protolist = slp;
+ }
+ endprotoent();
+}
+
+void
+res_destroyprotolist(void) {
+ struct valuelist *plp, *plp_next;
+
+ for (plp = protolist; plp != NULL; plp = plp_next) {
+ plp_next = plp->next;
+ free(plp->name);
+ free(plp);
+ }
+ protolist = (struct valuelist *)0;
+}
+
+static int
+findservice(const char *s, struct valuelist **list) {
+ struct valuelist *lp = *list;
+ int n;
+
+ for (; lp != NULL; lp = lp->next)
+ if (strcasecmp(lp->name, s) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ return (lp->port); /*%< host byte order */
+ }
+ if (sscanf(s, "%d", &n) != 1 || n <= 0)
+ n = -1;
+ return (n);
+}
+
+/*%
+ * Convert service name or (ascii) number to int.
+ */
+int
+res_servicenumber(const char *p) {
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ return (findservice(p, &servicelist));
+}
+
+/*%
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+res_protocolnumber(const char *p) {
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ return (findservice(p, &protolist));
+}
+
+static struct servent *
+cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ struct valuelist **list = &servicelist;
+ struct valuelist *lp = *list;
+ static struct servent serv;
+
+ port = ntohs(port);
+ for (; lp != NULL; lp = lp->next) {
+ if (port != (u_int16_t)lp->port) /*%< Host byte order. */
+ continue;
+ if (strcasecmp(lp->proto, proto) == 0) {
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ serv.s_name = lp->name;
+ serv.s_port = htons((u_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static struct protoent *
+cgetprotobynumber(int proto) { /*%< Host byte order. */
+ struct valuelist **list = &protolist;
+ struct valuelist *lp = *list;
+ static struct protoent prot;
+
+ for (; lp != NULL; lp = lp->next)
+ if (lp->port == proto) { /*%< Host byte order. */
+ if (lp != *list) {
+ lp->prev->next = lp->next;
+ if (lp->next)
+ lp->next->prev = lp->prev;
+ (*list)->prev = lp;
+ lp->next = *list;
+ *list = lp;
+ }
+ prot.p_name = lp->name;
+ prot.p_proto = lp->port; /*%< Host byte order. */
+ return (&prot);
+ }
+ return (0);
+}
+
+const char *
+res_protocolname(int num) {
+ static char number[8];
+ struct protoent *pp;
+
+ if (protolist == (struct valuelist *)0)
+ res_buildprotolist();
+ pp = cgetprotobynumber(num);
+ if (pp == 0) {
+ (void) sprintf(number, "%d", num);
+ return (number);
+ }
+ return (pp->p_name);
+}
+
+const char *
+res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
+ static char number[8];
+ struct servent *ss;
+
+ if (servicelist == (struct valuelist *)0)
+ res_buildservicelist();
+ ss = cgetservbyport(htons(port), proto);
+ if (ss == 0) {
+ (void) sprintf(number, "%d", port);
+ return (number);
+ }
+ return (ss->s_name);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.h b/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.h
new file mode 100644
index 0000000000..96c452d89e
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_mkupdate.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _RES_MKUPDATE_H_
+#define _RES_MKUPDATE_H_
+
+__BEGIN_DECLS
+__END_DECLS
+
+#endif /* _RES_MKUPDATE_H_ */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_private.h b/usr/src/lib/libresolv2_joy/common/resolv/res_private.h
new file mode 100644
index 0000000000..4e98157ced
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_private.h
@@ -0,0 +1,22 @@
+#ifndef res_private_h
+#define res_private_h
+
+struct __res_state_ext {
+ union res_sockaddr_union nsaddrs[MAXNS];
+ struct sort_list {
+ int af;
+ union {
+ struct in_addr ina;
+ struct in6_addr in6a;
+ } addr, mask;
+ } sort_list[MAXRESOLVSORT];
+ char nsuffix[64];
+ char nsuffix2[64];
+};
+
+extern int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa);
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_query.c b/usr/src/lib/libresolv2_joy/common/resolv/res_query.c
new file mode 100644
index 0000000000..09df3da1fc
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_query.c
@@ -0,0 +1,440 @@
+/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_query.c,v 1.11 2008/11/14 02:36:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options. Leave them on. */
+#define DEBUG
+
+#if PACKETSZ > 1024
+#define MAXPACKET PACKETSZ
+#else
+#define MAXPACKET 1024
+#endif
+
+/*%
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in H_ERRNO.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+int
+res_nquery(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer buffer */
+{
+ u_char buf[MAXPACKET];
+ HEADER *hp = (HEADER *) answer;
+ u_int oflags;
+ u_char *rdata;
+ int n;
+
+ oflags = statp->_flags;
+
+again:
+ hp->rcode = NOERROR; /*%< default */
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+ n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+ buf, sizeof(buf));
+#ifdef RES_USE_EDNS0
+ if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
+ (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) {
+ n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+ rdata = &buf[n];
+ if (n > 0 && (statp->options & RES_NSID) != 0U) {
+ n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata,
+ NS_OPT_NSID, 0, NULL);
+ }
+ }
+#endif
+ if (n <= 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: mkquery failed\n");
+#endif
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (n);
+ }
+
+ n = res_nsend(statp, buf, n, answer, anslen);
+ if (n < 0) {
+#ifdef RES_USE_EDNS0
+ /* if the query choked with EDNS0, retry without EDNS0 */
+ if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
+ ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+ statp->_flags |= RES_F_EDNS0ERR;
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquery: retry without EDNS0\n");
+ goto again;
+ }
+#endif
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_query: send error\n");
+#endif
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (n);
+ }
+
+ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
+ p_rcode(hp->rcode),
+ ntohs(hp->ancount),
+ ntohs(hp->nscount),
+ ntohs(hp->arcount));
+#endif
+ switch (hp->rcode) {
+ case NXDOMAIN:
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ break;
+ case SERVFAIL:
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ break;
+ case NOERROR:
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ break;
+ case FORMERR:
+ case NOTIMP:
+ case REFUSED:
+ default:
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ break;
+ }
+ return (-1);
+ }
+ return (n);
+}
+
+/*%
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in H_ERRNO.
+ */
+int
+res_nsearch(res_state statp,
+ const char *name, /*%< domain name */
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *) answer;
+ char tmp[NS_MAXDNAME];
+ u_int dots;
+ int trailing_dot, ret, saved_herrno;
+ int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+ int tried_as_is = 0;
+ int searched = 0;
+
+ errno = 0;
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /*%< True if we never query. */
+ dots = 0;
+ for (cp = name; *cp != '\0'; cp++)
+ dots += (*cp == '.');
+ trailing_dot = 0;
+ if (cp > name && *--cp == '.')
+ trailing_dot++;
+
+ /* If there aren't any dots, it could be a user-level alias. */
+ if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+ return (res_nquery(statp, cp, class, type, answer, anslen));
+
+ /*
+ * If there are enough dots in the name, let's just give it a
+ * try 'as is'. The threshold can be set with the "ndots" option.
+ * Also, query 'as is', if there is a trailing dot in the name.
+ */
+ saved_herrno = -1;
+ if (dots >= statp->ndots || trailing_dot) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0 || trailing_dot)
+ return (ret);
+ saved_herrno = statp->res_h_errno;
+ tried_as_is++;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (statp->options & RES_DEFNAMES) != 0U) ||
+ (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) {
+ int done = 0;
+
+ for (domain = (const char * const *)statp->dnsrch;
+ *domain && !done;
+ domain++) {
+ searched = 1;
+
+ if (domain[0][0] == '\0' ||
+ (domain[0][0] == '.' && domain[0][1] == '\0'))
+ root_on_list++;
+
+ ret = res_nquerydomain(statp, name, *domain,
+ class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ got_nodata++;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL) {
+ /* try next search element, if any */
+ got_servfail++;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done++;
+ }
+
+ /* if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if ((statp->options & RES_DNSRCH) == 0U)
+ done++;
+ }
+ }
+
+ /*
+ * If the query has not already been tried as is then try it
+ * unless RES_NOTLDQUERY is set and there were no dots.
+ */
+ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
+ !(tried_as_is || root_on_list)) {
+ ret = res_nquerydomain(statp, name, NULL, class, type,
+ answer, anslen);
+ if (ret > 0)
+ return (ret);
+ }
+
+ /* if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's H_ERRNO
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless H_ERRNO, that being the one from
+ * the last DNSRCH we did.
+ */
+ if (saved_herrno != -1)
+ RES_SET_H_ERRNO(statp, saved_herrno);
+ else if (got_nodata)
+ RES_SET_H_ERRNO(statp, NO_DATA);
+ else if (got_servfail)
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+}
+
+/*%
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain(res_state statp,
+ const char *name,
+ const char *domain,
+ int class, int type, /*%< class and type of query */
+ u_char *answer, /*%< buffer to put answer */
+ int anslen) /*%< size of answer */
+{
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+ int n, d;
+
+#ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+ printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
+ name, domain?domain:"<Nil>", class, type);
+#endif
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ n--;
+ if (n >= 0 && name[n] == '.') {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + d + 1 >= MAXDNAME) {
+ RES_SET_H_ERRNO(statp, NO_RECOVERY);
+ return (-1);
+ }
+ sprintf(nbuf, "%s.%s", name, domain);
+ }
+ return (res_nquery(statp, longname, class, type, answer, anslen));
+}
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+ char *file, *cp1, *cp2;
+ char buf[BUFSIZ];
+ FILE *fp;
+
+ if (statp->options & RES_NOALIASES)
+ return (NULL);
+ file = getenv("HOSTALIASES");
+ if (file == NULL || (fp = fopen(file, "r")) == NULL)
+ return (NULL);
+ setbuf(fp, NULL);
+ buf[sizeof(buf) - 1] = '\0';
+ while (fgets(buf, sizeof(buf), fp)) {
+ for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
+ ;
+ if (!*cp1)
+ break;
+ *cp1 = '\0';
+ if (ns_samename(buf, name) == 1) {
+ while (isspace((unsigned char)*++cp1))
+ ;
+ if (!*cp1)
+ break;
+ for (cp2 = cp1 + 1; *cp2 &&
+ !isspace((unsigned char)*cp2); ++cp2)
+ ;
+ *cp2 = '\0';
+ strncpy(dst, cp1, siz - 1);
+ dst[siz - 1] = '\0';
+ fclose(fp);
+ return (dst);
+ }
+ }
+ fclose(fp);
+ return (NULL);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_send.c b/usr/src/lib/libresolv2_joy/common/resolv/res_send.c
new file mode 100644
index 0000000000..289db4e77d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_send.c
@@ -0,0 +1,1120 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*! \file
+ * \brief
+ * Send query to name server and wait for reply.
+ */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+
+#include "port_after.h"
+
+#ifdef USE_POLL
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#include <poll.h>
+#endif /* USE_POLL */
+
+/* Options. Leave them on. */
+#define DEBUG
+#include "res_debug.h"
+#include "res_private.h"
+
+#define EXT(res) ((res)->_u._ext)
+
+#ifndef USE_POLL
+static const int highestFD = FD_SETSIZE - 1;
+#else
+static int highestFD = 0;
+#endif
+
+/* Forward. */
+
+static int get_salen __P((const struct sockaddr *));
+static struct sockaddr * get_nsaddr __P((res_state, size_t));
+static int send_vc(res_state, const u_char *, int,
+ u_char *, int, int *, int);
+static int send_dg(res_state, const u_char *, int,
+ u_char *, int, int *, int, int,
+ int *, int *);
+static void Aerror(const res_state, FILE *, const char *, int,
+ const struct sockaddr *, int);
+static void Perror(const res_state, FILE *, const char *, int);
+static int sock_eq(struct sockaddr *, struct sockaddr *);
+#if defined(NEED_PSELECT) && !defined(USE_POLL)
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
+#endif
+void res_pquery(const res_state, const u_char *, int, FILE *);
+
+#ifndef ORIGINAL_ISC_CODE
+#pragma weak __res_nameinquery = res_nameinquery
+#pragma weak __res_queriesmatch = res_queriesmatch
+#pragma weak res_nisourserver = res_ourserver_p
+#endif /* ORIGINAL_ISC_CODE */
+
+static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+/* Public. */
+
+/*%
+ * looks up "ina" in _res.ns_addr_list[]
+ *
+ * returns:
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
+ const struct sockaddr_in *inp, *srv;
+ const struct sockaddr_in6 *in6p, *srv6;
+ int ns;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ inp = (const struct sockaddr_in *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
+ if (srv->sin_family == inp->sin_family &&
+ srv->sin_port == inp->sin_port &&
+ (srv->sin_addr.s_addr == INADDR_ANY ||
+ srv->sin_addr.s_addr == inp->sin_addr.s_addr))
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (EXT(statp).ext == NULL)
+ break;
+ in6p = (const struct sockaddr_in6 *)sa;
+ for (ns = 0; ns < statp->nscount; ns++) {
+ srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
+ if (srv6->sin6_family == in6p->sin6_family &&
+ srv6->sin6_port == in6p->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ (srv6->sin6_scope_id == 0 ||
+ srv6->sin6_scope_id == in6p->sin6_scope_id) &&
+#endif
+ (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
+ IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*%
+ * look for (name,type,class) in the query section of packet (buf,eom)
+ *
+ * requires:
+ *\li buf + HFIXEDSZ <= eom
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not found
+ *\li >0 : found
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_nameinquery(const char *name, int type, int class,
+ const u_char *buf, const u_char *eom)
+{
+ const u_char *cp = buf + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf)->qdcount);
+
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf, eom, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (ttype == type && tclass == class &&
+ ns_samename(tname, name) == 1)
+ return (1);
+ }
+ return (0);
+}
+
+/*%
+ * is there a 1:1 mapping of (name,type,class)
+ * in (buf1,eom1) and (buf2,eom2)?
+ *
+ * returns:
+ *\li -1 : format error
+ *\li 0 : not a 1:1 mapping
+ *\li >0 : is a 1:1 mapping
+ *
+ * author:
+ *\li paul vixie, 29may94
+ */
+int
+res_queriesmatch(const u_char *buf1, const u_char *eom1,
+ const u_char *buf2, const u_char *eom2)
+{
+ const u_char *cp = buf1 + HFIXEDSZ;
+ int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
+
+ if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
+ return (-1);
+
+ /*
+ * Only header section present in replies to
+ * dynamic update packets.
+ */
+ if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
+ (((const HEADER *)buf2)->opcode == ns_o_update))
+ return (1);
+
+ if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
+ return (0);
+ while (qdcount-- > 0) {
+ char tname[MAXDNAME+1];
+ int n, ttype, tclass;
+
+ n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (cp + 2 * INT16SZ > eom1)
+ return (-1);
+ ttype = ns_get16(cp); cp += INT16SZ;
+ tclass = ns_get16(cp); cp += INT16SZ;
+ if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
+ return (0);
+ }
+ return (1);
+}
+
+int
+res_nsend(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+ int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
+ char abuf[NI_MAXHOST];
+
+#ifdef USE_POLL
+ highestFD = sysconf(_SC_OPEN_MAX) - 1;
+#endif
+
+ /* No name servers or res_init() failure */
+ if (statp->nscount == 0 || EXT(statp).ext == NULL) {
+ errno = ESRCH;
+ return (-1);
+ }
+ if (anssiz < HFIXEDSZ) {
+ errno = EINVAL;
+ return (-1);
+ }
+ DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
+ (stdout, ";; res_send()\n"), buf, buflen);
+ v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
+ gotsomewhere = 0;
+ terrno = ETIMEDOUT;
+
+ /*
+ * If the ns_addr_list in the resolver context has changed, then
+ * invalidate our cached copy and the associated timing data.
+ */
+ if (EXT(statp).nscount != 0) {
+ int needclose = 0;
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T peerlen;
+
+ if (EXT(statp).nscount != statp->nscount)
+ needclose++;
+ else
+ for (ns = 0; ns < statp->nscount; ns++) {
+ if (statp->nsaddr_list[ns].sin_family &&
+ !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
+ (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
+ needclose++;
+ break;
+ }
+
+ if (EXT(statp).nssocks[ns] == -1)
+ continue;
+ peerlen = sizeof(peer);
+ if (getpeername(EXT(statp).nssocks[ns],
+ (struct sockaddr *)&peer, &peerlen) < 0) {
+ needclose++;
+ break;
+ }
+ if (!sock_eq((struct sockaddr *)&peer,
+ get_nsaddr(statp, ns))) {
+ needclose++;
+ break;
+ }
+ }
+ if (needclose) {
+ res_nclose(statp);
+ EXT(statp).nscount = 0;
+ }
+ }
+
+ /*
+ * Maybe initialize our private copy of the ns_addr_list.
+ */
+ if (EXT(statp).nscount == 0) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ EXT(statp).nstimes[ns] = RES_MAXTIME;
+ EXT(statp).nssocks[ns] = -1;
+ if (!statp->nsaddr_list[ns].sin_family)
+ continue;
+ EXT(statp).ext->nsaddrs[ns].sin =
+ statp->nsaddr_list[ns];
+ }
+ EXT(statp).nscount = statp->nscount;
+ }
+
+ /*
+ * Some resolvers want to even out the load on their nameservers.
+ * Note that RES_BLAST overrides RES_ROTATE.
+ */
+ if ((statp->options & RES_ROTATE) != 0U &&
+ (statp->options & RES_BLAST) == 0U) {
+ union res_sockaddr_union inu;
+ struct sockaddr_in ina;
+ int lastns = statp->nscount - 1;
+ int fd;
+ u_int16_t nstime;
+
+ if (EXT(statp).ext != NULL)
+ inu = EXT(statp).ext->nsaddrs[0];
+ ina = statp->nsaddr_list[0];
+ fd = EXT(statp).nssocks[0];
+ nstime = EXT(statp).nstimes[0];
+ for (ns = 0; ns < lastns; ns++) {
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[ns] =
+ EXT(statp).ext->nsaddrs[ns + 1];
+ statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+ EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
+ EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
+ }
+ if (EXT(statp).ext != NULL)
+ EXT(statp).ext->nsaddrs[lastns] = inu;
+ statp->nsaddr_list[lastns] = ina;
+ EXT(statp).nssocks[lastns] = fd;
+ EXT(statp).nstimes[lastns] = nstime;
+ }
+
+ /*
+ * Send request, RETRY times, or until successful.
+ */
+ for (tries = 0; tries < statp->retry; tries++) {
+ for (ns = 0; ns < statp->nscount; ns++) {
+ struct sockaddr *nsap;
+ int nsaplen;
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ statp->_flags &= ~RES_F_LASTMASK;
+ statp->_flags |= (ns << RES_F_LASTSHIFT);
+ same_ns:
+ if (statp->qhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->qhook)(&nsap, &buf, &buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_done:
+ return (resplen);
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+ }
+
+ Dprint(((statp->options & RES_DEBUG) &&
+ getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
+ NULL, 0, niflags) == 0),
+ (stdout, ";; Querying server (# %d) address = %s\n",
+ ns + 1, abuf));
+
+
+ if (v_circuit) {
+ /* Use VC; at most one attempt per server. */
+ tries = statp->retry;
+ n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
+ ns);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ resplen = n;
+ } else {
+ /* Use datagrams. */
+ n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+ ns, tries, &v_circuit, &gotsomewhere);
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ goto next_ns;
+ if (v_circuit)
+ goto same_ns;
+ resplen = n;
+ }
+
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+
+ /*
+ * If we have temporarily opened a virtual circuit,
+ * or if we haven't been asked to keep a socket open,
+ * close the socket.
+ */
+ if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
+ (statp->options & RES_STAYOPEN) == 0U) {
+ res_nclose(statp);
+ }
+ if (statp->rhook) {
+ int done = 0, loops = 0;
+
+ do {
+ res_sendhookact act;
+
+ act = (*statp->rhook)(nsap, buf, buflen,
+ ans, anssiz, &resplen);
+ switch (act) {
+ case res_goahead:
+ case res_done:
+ done = 1;
+ break;
+ case res_nextns:
+ res_nclose(statp);
+ goto next_ns;
+ case res_modified:
+ /* give the hook another try */
+ if (++loops < 42) /*doug adams*/
+ break;
+ /*FALLTHROUGH*/
+ case res_error:
+ /*FALLTHROUGH*/
+ default:
+ goto fail;
+ }
+ } while (!done);
+
+ }
+ return (resplen);
+ next_ns: ;
+ } /*foreach ns*/
+ } /*foreach retry*/
+ res_nclose(statp);
+ if (!v_circuit) {
+ if (!gotsomewhere)
+ errno = ECONNREFUSED; /*%< no nameservers found */
+ else
+ errno = ETIMEDOUT; /*%< no answer obtained */
+ } else
+ errno = terrno;
+ return (-1);
+ fail:
+ res_nclose(statp);
+ return (-1);
+}
+
+/* Private */
+
+static int
+get_salen(sa)
+ const struct sockaddr *sa;
+{
+
+#ifdef HAVE_SA_LEN
+ /* There are people do not set sa_len. Be forgiving to them. */
+ if (sa->sa_len)
+ return (sa->sa_len);
+#endif
+
+ if (sa->sa_family == AF_INET)
+ return (sizeof(struct sockaddr_in));
+ else if (sa->sa_family == AF_INET6)
+ return (sizeof(struct sockaddr_in6));
+ else
+ return (0); /*%< unknown, die on connect */
+}
+
+/*%
+ * pick appropriate nsaddr_list for use. see res_init() for initialization.
+ */
+static struct sockaddr *
+get_nsaddr(statp, n)
+ res_state statp;
+ size_t n;
+{
+
+ if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
+ /*
+ * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+ * than struct sockaddr, and
+ * - user code did not update statp->nsaddr_list[n].
+ */
+ return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
+ } else {
+ /*
+ * - user code updated statp->nsaddr_list[n], or
+ * - statp->nsaddr_list[n] has the same content as
+ * EXT(statp).ext->nsaddrs[n].
+ */
+ return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+ }
+}
+
+static int
+send_vc(res_state statp,
+ const u_char *buf, int buflen, u_char *ans, int anssiz,
+ int *terrno, int ns)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ struct sockaddr *nsap;
+ int nsaplen;
+ int truncating, connreset, resplen, n;
+ struct iovec iov[2];
+ u_short len;
+ u_char *cp;
+ void *tmp;
+#ifdef SO_NOSIGPIPE
+ int on = 1;
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+
+ connreset = 0;
+ same_ns:
+ truncating = 0;
+
+ /* Are we still talking to whom we want to talk to? */
+ if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
+ struct sockaddr_storage peer;
+ ISC_SOCKLEN_T size = sizeof peer;
+
+ if (getpeername(statp->_vcsock,
+ (struct sockaddr *)&peer, &size) < 0 ||
+ !sock_eq((struct sockaddr *)&peer, nsap)) {
+ res_nclose(statp);
+ statp->_flags &= ~RES_F_VC;
+ }
+ }
+
+ if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
+ if (statp->_vcsock >= 0)
+ res_nclose(statp);
+
+ statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ if (statp->_vcsock > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+ if (statp->_vcsock < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(vc)", errno);
+ return (-1);
+ }
+ }
+#ifdef SO_NOSIGPIPE
+ /*
+ * Disable generation of SIGPIPE when writing to a closed
+ * socket. Write should return -1 and set errno to EPIPE
+ * instead.
+ *
+ * Push on even if setsockopt(SO_NOSIGPIPE) fails.
+ */
+ (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
+ sizeof(on));
+#endif
+ errno = 0;
+ if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect/vc", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+ statp->_flags |= RES_F_VC;
+ }
+
+ /*
+ * Send length & message
+ */
+ ns_put16((u_short)buflen, (u_char*)&len);
+ iov[0] = evConsIovec(&len, INT16SZ);
+ DE_CONST(buf, tmp);
+ iov[1] = evConsIovec(tmp, buflen);
+ if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+ *terrno = errno;
+ Perror(statp, stderr, "write failed", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ /*
+ * Receive length & response
+ */
+ read_len:
+ cp = ans;
+ len = INT16SZ;
+ while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ if ((len -= n) == 0)
+ break;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read failed", errno);
+ res_nclose(statp);
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+ * restarted. Requery the server instead of
+ * trying a new one. When there is only one
+ * server, this means that a query might work
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+ if (*terrno == ECONNRESET && !connreset) {
+ connreset = 1;
+ res_nclose(statp);
+ goto same_ns;
+ }
+ res_nclose(statp);
+ return (0);
+ }
+ resplen = ns_get16(ans);
+ if (resplen > anssiz) {
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; response truncated\n")
+ );
+ truncating = 1;
+ len = anssiz;
+ } else
+ len = resplen;
+ if (len < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n", len));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ cp = ans;
+ while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read(vc)", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ if (truncating) {
+ /*
+ * Flush rest of answer so connection stays in synch.
+ */
+ anhp->tc = 1;
+ len = resplen - anssiz;
+ while (len != 0) {
+ char junk[PACKETSZ];
+
+ n = read(statp->_vcsock, junk,
+ (len > sizeof junk) ? sizeof junk : len);
+ if (n > 0)
+ len -= n;
+ else
+ break;
+ }
+ }
+ /*
+ * If the calling applicating has bailed out of
+ * a previous call and failed to arrange to have
+ * the circuit closed or the server has got
+ * itself confused, then drop the packet and
+ * wait for the correct one.
+ */
+ if (hp->id != anhp->id) {
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer (unexpected):\n"),
+ ans, (resplen > anssiz) ? anssiz: resplen);
+ goto read_len;
+ }
+
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static int
+send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
+ int anssiz, int *terrno, int ns, int tries, int *v_circuit,
+ int *gotsomewhere)
+{
+ const HEADER *hp = (const HEADER *) buf;
+ HEADER *anhp = (HEADER *) ans;
+ const struct sockaddr *nsap;
+ int nsaplen;
+ struct timespec now, timeout, finish;
+ struct sockaddr_storage from;
+ ISC_SOCKLEN_T fromlen;
+ int resplen, seconds, n, s;
+#ifdef USE_POLL
+ int polltimeout;
+ struct pollfd pollfd;
+#else
+ fd_set dsmask;
+#endif
+
+ nsap = get_nsaddr(statp, ns);
+ nsaplen = get_salen(nsap);
+ if (EXT(statp).nssocks[ns] == -1) {
+ EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+ if (EXT(statp).nssocks[ns] > highestFD) {
+ res_nclose(statp);
+ errno = ENOTSOCK;
+ }
+ if (EXT(statp).nssocks[ns] < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+#ifdef EPFNOSUPPORT
+ case EPFNOSUPPORT:
+#endif
+ case EAFNOSUPPORT:
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (0);
+ default:
+ *terrno = errno;
+ Perror(statp, stderr, "socket(dg)", errno);
+ return (-1);
+ }
+ }
+#ifndef CANNOT_CONNECT_DGRAM
+ /*
+ * On a 4.3BSD+ machine (client and server,
+ * actually), sending to a nameserver datagram
+ * port with no nameserver will cause an
+ * ICMP port unreachable message to be returned.
+ * If our datagram socket is "connected" to the
+ * server, we get an ECONNREFUSED error on the next
+ * socket operation, and select returns if the
+ * error message is received. We can thus detect
+ * the absence of a nameserver without timing out.
+ */
+ if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+ Aerror(statp, stderr, "connect(dg)", errno, nsap,
+ nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; new DG socket\n"))
+ }
+ s = EXT(statp).nssocks[ns];
+#ifndef CANNOT_CONNECT_DGRAM
+ if (send(s, (const char*)buf, buflen, 0) != buflen) {
+ Perror(statp, stderr, "send", errno);
+ res_nclose(statp);
+ return (0);
+ }
+#else /* !CANNOT_CONNECT_DGRAM */
+ if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+ /*
+ * Wait for reply.
+ */
+ seconds = (statp->retrans << tries);
+ if (ns > 0)
+ seconds /= statp->nscount;
+ if (seconds <= 0)
+ seconds = 1;
+ now = evNowTime();
+ timeout = evConsTime(seconds, 0);
+ finish = evAddTime(now, timeout);
+ goto nonow;
+ wait:
+ now = evNowTime();
+ nonow:
+#ifndef USE_POLL
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
+ if (evCmpTime(finish, now) > 0)
+ timeout = evSubTime(finish, now);
+ else
+ timeout = evConsTime(0, 0);
+ n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+#else
+ timeout = evSubTime(finish, now);
+ if (timeout.tv_sec < 0)
+ timeout = evConsTime(0, 0);
+ polltimeout = 1000*timeout.tv_sec +
+ timeout.tv_nsec/1000000;
+ pollfd.fd = s;
+ pollfd.events = POLLRDNORM;
+ n = poll(&pollfd, 1, polltimeout);
+#endif /* USE_POLL */
+
+ if (n == 0) {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
+ *gotsomewhere = 1;
+ return (0);
+ }
+ if (n < 0) {
+ if (errno == EINTR)
+ goto wait;
+#ifndef USE_POLL
+ Perror(statp, stderr, "select", errno);
+#else
+ Perror(statp, stderr, "poll", errno);
+#endif /* USE_POLL */
+ res_nclose(statp);
+ return (0);
+ }
+ errno = 0;
+ fromlen = sizeof(from);
+ resplen = recvfrom(s, (char*)ans, anssiz,0,
+ (struct sockaddr *)&from, &fromlen);
+ if (resplen <= 0) {
+ Perror(statp, stderr, "recvfrom", errno);
+ res_nclose(statp);
+ return (0);
+ }
+ *gotsomewhere = 1;
+ if (resplen < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n",
+ resplen));
+ *terrno = EMSGSIZE;
+ res_nclose(statp);
+ return (0);
+ }
+ if (hp->id != anhp->id) {
+ /*
+ * response from old query, ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; old answer:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (!(statp->options & RES_INSECURE1) &&
+ !res_ourserver_p(statp, (struct sockaddr *)&from)) {
+ /*
+ * response from wrong server? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; not our server:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+#ifdef RES_USE_EDNS0
+ if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
+ /*
+ * Do not retry if the server do not understand EDNS0.
+ * The case has to be captured here, as FORMERR packet do not
+ * carry query section, hence res_queriesmatch() returns 0.
+ */
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query with EDNS0:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ /* record the error */
+ statp->_flags |= RES_F_EDNS0ERR;
+ res_nclose(statp);
+ return (0);
+ }
+#endif
+ if (!(statp->options & RES_INSECURE2) &&
+ !res_queriesmatch(buf, buf + buflen,
+ ans, ans + anssiz)) {
+ /*
+ * response contains wrong query? ignore it.
+ * XXX - potential security hazard could
+ * be detected here.
+ */
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, ";; wrong query name:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ goto wait;
+ }
+ if (anhp->rcode == SERVFAIL ||
+ anhp->rcode == NOTIMP ||
+ anhp->rcode == REFUSED) {
+ DprintQ(statp->options & RES_DEBUG,
+ (stdout, "server rejected query:\n"),
+ ans, (resplen > anssiz) ? anssiz : resplen);
+ res_nclose(statp);
+ /* don't retry if called from dig */
+ if (!statp->pfcode)
+ return (0);
+ }
+ if (!(statp->options & RES_IGNTC) && anhp->tc) {
+ /*
+ * To get the rest of answer,
+ * use TCP with same server.
+ */
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; truncated answer\n"));
+ *v_circuit = 1;
+ res_nclose(statp);
+ return (1);
+ }
+ /*
+ * All is well, or the error is fatal. Signal that the
+ * next nameserver ought not be tried.
+ */
+ return (resplen);
+}
+
+static void
+Aerror(const res_state statp, FILE *file, const char *string, int error,
+ const struct sockaddr *address, int alen)
+{
+ int save = errno;
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+
+ alen = alen;
+
+ if ((statp->options & RES_DEBUG) != 0U) {
+ if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), niflags)) {
+ strncpy(hbuf, "?", sizeof(hbuf) - 1);
+ hbuf[sizeof(hbuf) - 1] = '\0';
+ strncpy(sbuf, "?", sizeof(sbuf) - 1);
+ sbuf[sizeof(sbuf) - 1] = '\0';
+ }
+ fprintf(file, "res_send: %s ([%s].%s): %s\n",
+ string, hbuf, sbuf, strerror(error));
+ }
+ errno = save;
+}
+
+static void
+Perror(const res_state statp, FILE *file, const char *string, int error) {
+ int save = errno;
+
+ if ((statp->options & RES_DEBUG) != 0U)
+ fprintf(file, "res_send: %s: %s\n",
+ string, strerror(error));
+ errno = save;
+}
+
+static int
+sock_eq(struct sockaddr *a, struct sockaddr *b) {
+ struct sockaddr_in *a4, *b4;
+ struct sockaddr_in6 *a6, *b6;
+
+ if (a->sa_family != b->sa_family)
+ return 0;
+ switch (a->sa_family) {
+ case AF_INET:
+ a4 = (struct sockaddr_in *)a;
+ b4 = (struct sockaddr_in *)b;
+ return a4->sin_port == b4->sin_port &&
+ a4->sin_addr.s_addr == b4->sin_addr.s_addr;
+ case AF_INET6:
+ a6 = (struct sockaddr_in6 *)a;
+ b6 = (struct sockaddr_in6 *)b;
+ return a6->sin6_port == b6->sin6_port &&
+#ifdef HAVE_SIN6_SCOPE_ID
+ a6->sin6_scope_id == b6->sin6_scope_id &&
+#endif
+ IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
+ default:
+ return 0;
+ }
+}
+
+#if defined(NEED_PSELECT) && !defined(USE_POLL)
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp, const sigset_t *sigmask)
+{
+ struct timeval tv, *tvp;
+ sigset_t sigs;
+ int n;
+
+ if (tsp) {
+ tvp = &tv;
+ tv = evTimeVal(*tsp);
+ } else
+ tvp = NULL;
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, sigmask, &sigs);
+ n = select(nfds, rfds, wfds, efds, tvp);
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+ if (tsp)
+ *tsp = evTimeSpec(tv);
+ return (n);
+}
+#endif
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_sendsigned.c b/usr/src/lib/libresolv2_joy/common/resolv/res_sendsigned.c
new file mode 100644
index 0000000000..5ebc1a70eb
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_sendsigned.c
@@ -0,0 +1,170 @@
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/dst.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#define DEBUG
+#include "res_debug.h"
+
+
+/*% res_nsendsigned */
+int
+res_nsendsigned(res_state statp, const u_char *msg, int msglen,
+ ns_tsig_key *key, u_char *answer, int anslen)
+{
+ res_state nstatp;
+ DST_KEY *dstkey;
+ int usingTCP = 0;
+ u_char *newmsg;
+ int newmsglen, bufsize, siglen;
+ u_char sig[64];
+ HEADER *hp;
+ time_t tsig_time;
+ int ret;
+ int len;
+
+ dst_init();
+
+ nstatp = (res_state) malloc(sizeof(*statp));
+ if (nstatp == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(nstatp, statp, sizeof(*statp));
+
+ bufsize = msglen + 1024;
+ newmsg = (u_char *) malloc(bufsize);
+ if (newmsg == NULL) {
+ free(nstatp);
+ errno = ENOMEM;
+ return (-1);
+ }
+ memcpy(newmsg, msg, msglen);
+ newmsglen = msglen;
+
+ if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+ dstkey = NULL;
+ else
+ dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
+ NS_KEY_TYPE_AUTH_ONLY,
+ NS_KEY_PROT_ANY,
+ key->data, key->len);
+ if (dstkey == NULL) {
+ errno = EINVAL;
+ free(nstatp);
+ free(newmsg);
+ return (-1);
+ }
+
+ nstatp->nscount = 1;
+ siglen = sizeof(sig);
+ ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
+ sig, &siglen, 0);
+ if (ret < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == NS_TSIG_ERROR_NO_SPACE)
+ errno = EMSGSIZE;
+ else if (ret == -1)
+ errno = EINVAL;
+ return (ret);
+ }
+
+ if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC)
+ usingTCP = 1;
+ if (usingTCP == 0)
+ nstatp->options |= RES_IGNTC;
+ else
+ nstatp->options |= RES_USEVC;
+ /*
+ * Stop res_send printing the answer.
+ */
+ nstatp->options &= ~RES_DEBUG;
+ nstatp->pfcode &= ~RES_PRF_REPLY;
+
+retry:
+
+ len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
+ if (len < 0) {
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (len);
+ }
+
+ ret = ns_verify(answer, &len, dstkey, sig, siglen,
+ NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
+ if (ret != 0) {
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ answer, (anslen > len) ? len : anslen);
+
+ if (ret > 0) {
+ Dprint(statp->pfcode & RES_PRF_REPLY,
+ (stdout, ";; server rejected TSIG (%s)\n",
+ p_rcode(ret)));
+ } else {
+ Dprint(statp->pfcode & RES_PRF_REPLY,
+ (stdout, ";; TSIG invalid (%s)\n",
+ p_rcode(-ret)));
+ }
+
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ if (ret == -1)
+ errno = EINVAL;
+ else
+ errno = ENOTTY;
+ return (-1);
+ }
+
+ hp = (HEADER *) answer;
+ if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) {
+ nstatp->options &= ~RES_IGNTC;
+ usingTCP = 1;
+ goto retry;
+ }
+ Dprint((statp->options & RES_DEBUG) ||
+ ((statp->pfcode & RES_PRF_REPLY) &&
+ (statp->pfcode & RES_PRF_HEAD1)),
+ (stdout, ";; got answer:\n"));
+
+ DprintQ((statp->options & RES_DEBUG) ||
+ (statp->pfcode & RES_PRF_REPLY),
+ (stdout, "%s", ""),
+ answer, (anslen > len) ? len : anslen);
+
+ Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
+
+ free (nstatp);
+ free (newmsg);
+ dst_free_key(dstkey);
+ return (len);
+}
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/common/resolv/res_update.c b/usr/src/lib/libresolv2_joy/common/resolv/res_update.c
new file mode 100644
index 0000000000..df24aee3bd
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/resolv/res_update.c
@@ -0,0 +1,213 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.13 2005/04/27 04:56:43 sra Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * &lt;viraj_bais@ccm.fm.intel.com>
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <res_update.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+#include <resolv_joy.h>
+
+#include "port_after.h"
+#include "res_private.h"
+
+/*%
+ * Separate a linked list of records into groups so that all records
+ * in a group will belong to a single zone on the nameserver.
+ * Create a dynamic update packet for each zone and send it to the
+ * nameservers for that zone, and await answer.
+ * Abort if error occurs in updating any zone.
+ * Return the number of zones updated on success, < 0 on error.
+ *
+ * On error, caller must deal with the unsynchronized zones
+ * eg. an A record might have been successfully added to the forward
+ * zone but the corresponding PTR record would be missing if error
+ * was encountered while updating the reverse zone.
+ */
+
+struct zonegrp {
+ char z_origin[MAXDNAME];
+ ns_class z_class;
+ union res_sockaddr_union z_nsaddrs[MAXNS];
+ int z_nscount;
+ int z_flags;
+ LIST(ns_updrec) z_rrlist;
+ LINK(struct zonegrp) z_link;
+};
+
+#define ZG_F_ZONESECTADDED 0x0001
+
+/* Forward. */
+
+static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+ int save_errno = errno; \
+ if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
+ errno = save_errno; \
+ } while (0)
+
+/* Public. */
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+ ns_updrec *rrecp;
+ u_char answer[PACKETSZ];
+ u_char *packet;
+ struct zonegrp *zptr, tgrp;
+ LIST(struct zonegrp) zgrps;
+ int nzones = 0, nscount = 0, n;
+ union res_sockaddr_union nsaddrs[MAXNS];
+
+ packet = malloc(NS_MAXMSG);
+ if (packet == NULL) {
+ DPRINTF(("malloc failed"));
+ return (0);
+ }
+ /* Thread all of the updates onto a list of groups. */
+ INIT_LIST(zgrps);
+ memset(&tgrp, 0, sizeof (tgrp));
+ for (rrecp = rrecp_in; rrecp;
+ rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
+ int nscnt;
+ /* Find the origin for it if there is one. */
+ tgrp.z_class = rrecp->r_class;
+ nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
+ RES_EXHAUSTIVE, tgrp.z_origin,
+ sizeof tgrp.z_origin,
+ tgrp.z_nsaddrs, MAXNS);
+ if (nscnt <= 0) {
+ DPRINTF(("res_findzonecut failed (%d)", nscnt));
+ goto done;
+ }
+ tgrp.z_nscount = nscnt;
+ /* Find the group for it if there is one. */
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
+ if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+ tgrp.z_class == zptr->z_class)
+ break;
+ /* Make a group for it if there isn't one. */
+ if (zptr == NULL) {
+ zptr = malloc(sizeof *zptr);
+ if (zptr == NULL) {
+ DPRINTF(("malloc failed"));
+ goto done;
+ }
+ *zptr = tgrp;
+ zptr->z_flags = 0;
+ INIT_LINK(zptr, z_link);
+ INIT_LIST(zptr->z_rrlist);
+ APPEND(zgrps, zptr, z_link);
+ }
+ /* Thread this rrecp onto the right group. */
+ APPEND(zptr->z_rrlist, rrecp, r_glink);
+ }
+
+ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
+ /* Construct zone section and prepend it. */
+ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+ zptr->z_class, ns_t_soa, 0);
+ if (rrecp == NULL) {
+ DPRINTF(("res_mkupdrec failed"));
+ goto done;
+ }
+ PREPEND(zptr->z_rrlist, rrecp, r_glink);
+ zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+ /* Marshall the update message. */
+ n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
+ packet, NS_MAXMSG);
+ DPRINTF(("res_mkupdate -> %d", n));
+ if (n < 0)
+ goto done;
+
+ /* Temporarily replace the resolver's nameserver set. */
+ nscount = res_getservers(statp, nsaddrs, MAXNS);
+ res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);
+
+ /* Send the update and remember the result. */
+ if (key != NULL)
+ n = res_nsendsigned(statp, packet, n, key,
+ answer, sizeof answer);
+ else
+ n = res_nsend(statp, packet, n, answer, sizeof answer);
+ if (n < 0) {
+ DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+ n, strerror(errno)));
+ goto done;
+ }
+ if (((HEADER *)answer)->rcode == NOERROR)
+ nzones++;
+
+ /* Restore resolver's nameserver set. */
+ res_setservers(statp, nsaddrs, nscount);
+ nscount = 0;
+ }
+ done:
+ while (!EMPTY(zgrps)) {
+ zptr = HEAD(zgrps);
+ if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+ res_freeupdrec(HEAD(zptr->z_rrlist));
+ UNLINK(zgrps, zptr, z_link);
+ free(zptr);
+ }
+ if (nscount != 0)
+ res_setservers(statp, nsaddrs, nscount);
+
+ free(packet);
+ return (nzones);
+}
+
+/* Private. */
+
+static void
+res_dprintf(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs(";; res_nupdate: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/sunw/sunw_mtctxres.c b/usr/src/lib/libresolv2_joy/common/sunw/sunw_mtctxres.c
new file mode 100644
index 0000000000..cc2a485ede
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/sunw/sunw_mtctxres.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <port_before.h>
+#include <thread.h>
+#include <errno.h>
+#include <netdb.h>
+#include <malloc.h>
+#include <string.h>
+#include <resolv_mt.h>
+#include <irs.h>
+#include <port_after.h>
+
+#pragma redefine_extname __h_errno __joy_h_errno
+
+/*
+ * much of the original version of sunw_mtxtxres.c was incorporated into
+ * ISC libbind as resolv/mtctxres.c. The following bits have not yet made
+ * it into ISC libbind.
+ */
+
+/*
+ * There used to be a private, MT-safe resolver interface that used TSD
+ * to store per-thread _res, h_errno, etc. We continue to provide the
+ * access functions __res_get_res() and __res_get_h_errno() so that binaries
+ * that used the private interface will continue to work.
+ */
+
+#ifdef _res
+#undef _res
+#endif
+
+extern struct __res_state *__res_state(void);
+
+struct __res_state *
+__res_get_res(void) {
+ return (__res_state());
+}
+
+
+#ifdef h_errno
+#undef h_errno
+#endif
+
+extern int *__h_errno(void);
+
+int *
+__res_get_h_errno(void) {
+ return (__h_errno());
+}
+
+
+#ifdef SUNW_HOSTS_FALLBACK
+
+/*
+ * When the name service switch calls libresolv, it doesn't want fallback
+ * to /etc/hosts, so we provide a method to turn it off.
+ */
+
+void
+__joy_res_set_no_hosts_fallback(void) {
+ ___mtctxres()->no_hosts_fallback_private = 1;
+}
+
+void
+__joy_res_unset_no_hosts_fallback(void) {
+ ___mtctxres()->no_hosts_fallback_private = 0;
+}
+
+int
+__res_no_hosts_fallback(void) {
+ return (___mtctxres()->no_hosts_fallback_private);
+}
+
+#endif /* SUNW_HOSTS_FALLBACK */
+
+#ifdef SUNW_OVERRIDE_RETRY
+
+/*
+ * The NS switch wants to be able to override the number of retries.
+ */
+
+int
+__joy_res_override_retry(int retry) {
+ ___mtctxres()->retry_private = retry;
+ /*
+ * This function doesn't really need a return value; saving the
+ * old retry setting, and restoring it, is handled by __res_retry()
+ * and __res_retry_reset() below. However, the nss_dns library
+ * must have a private version of this function to be used when
+ * running with an old libresolv. That private nss_dns function
+ * needs a return value, and a function pointer is used to select
+ * the right function at runtime. Thus, __res_override_retry
+ * must have a function prototype consistent with the private
+ * nss_dns function, i.e., one that returns an int.
+ *
+ * Given that we do have a return value, that value must be zero.
+ * That's because retry_private == 0 is used to indicate that
+ * no override retry value is in effect, and the way we expect
+ * nss_dns to call us is:
+ *
+ * int oldretry = __res_override_retry(N);
+ * <whatever>
+ * (void)__res_override_retry(old_retry);
+ */
+ return (0);
+}
+
+int
+__res_retry(int retry) {
+ mtctxres_t *mt = ___mtctxres();
+
+ mt->retry_save = retry;
+ return ((mt->retry_private != 0) ? mt->retry_private : retry);
+}
+
+int
+__res_retry_reset(void) {
+ mtctxres_t *mt = ___mtctxres();
+
+ return (mt->retry_save);
+}
+
+#endif /* SUNW_OVERRIDE_RETRY */
diff --git a/usr/src/lib/libresolv2_joy/common/sunw/sunw_updrec.c b/usr/src/lib/libresolv2_joy/common/sunw/sunw_updrec.c
new file mode 100644
index 0000000000..3b0ffc49df
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/sunw/sunw_updrec.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * As of BIND 8.2.2, ISC (a) removed res_mkupdate(), res_update(), and
+ * res_mkupdrec() from what they consider the supported interface. The
+ * functions still exist, but their calling interface has changed, since
+ * the ns_updrec structure has changed.
+ *
+ * It seems probable that res_mkupdate() etc. will return, though possibly
+ * with other changes, in some future BIND release. In order to avoid
+ * going to PSARC twice (once to remove the functions, and then again to
+ * add them back), we retain the old interface as a wrapper around the
+ * new one.
+ */
+
+#include <port_before.h>
+
+#include <malloc.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/* get the Solaris ns_updrec before any renaming happens */
+#include <arpa/nameser.h>
+
+/* get the __ISC_ns_updrec */
+#include <res_update.h>
+
+#include <port_after.h>
+
+/* un-rename ns_updrec and res_* functions so we can wrap them */
+#undef ns_updrec
+#undef res_mkupdate
+#undef res_update
+#undef res_mkupdrec
+#undef res_freeupdrec
+#undef res_nmkupdate
+#undef res_nupdate
+
+void res_freeupdrec(ns_updrec *);
+
+static int
+old2new(ns_updrec *old, __ISC_ns_updrec *new) {
+
+ if (old->r_dname != 0) {
+ if ((new->r_dname = strdup(old->r_dname)) == 0)
+ return (-1);
+ } else {
+ new->r_dname = 0;
+ }
+
+ new->r_glink.prev =
+ new->r_glink.next =
+ new->r_link.prev =
+ new->r_link.next = 0;
+
+ new->r_section = old->r_section;
+ new->r_class = old->r_class;
+ new->r_type = old->r_type;
+ new->r_ttl = old->r_ttl;
+ new->r_data = old->r_data;
+ new->r_size = old->r_size;
+ new->r_opcode = old->r_opcode;
+ new->r_dp = old->r_dp;
+ new->r_deldp = old->r_deldp;
+ new->r_zone = old->r_zone;
+
+ return (0);
+}
+
+
+static int
+new2old(__ISC_ns_updrec *new, ns_updrec *old) {
+ /* XXX r_prev and r_next unchanged */
+ if (new->r_dname != 0) {
+ if ((old->r_dname = strdup(new->r_dname)) == 0)
+ return (-1);
+ } else {
+ old->r_dname = 0;
+ }
+ old->r_section = new->r_section;
+ old->r_class = new->r_class;
+ old->r_type = new->r_type;
+ old->r_ttl = new->r_ttl;
+ old->r_data = new->r_data;
+ old->r_size = new->r_size;
+ old->r_opcode = new->r_opcode;
+ old->r_grpnext = 0; /* XXX */
+ old->r_dp = new->r_dp;
+ old->r_deldp = new->r_deldp;
+ old->r_zone = new->r_zone;
+
+ return (0);
+}
+
+
+static void
+delete_list(__ISC_ns_updrec *list) {
+
+ __ISC_ns_updrec *next;
+
+ for (; list != 0; list = next) {
+ next = list->r_link.next;
+ __ISC_res_freeupdrec(list);
+ }
+}
+
+
+static __ISC_ns_updrec *
+copy_list(ns_updrec *old, int do_glink) {
+
+ __ISC_ns_updrec *list = 0, *r, *p;
+
+ if (old == 0)
+ return (0);
+
+ for (p = 0; old != 0; old = old->r_next, p = r) {
+ if ((r = calloc(1, sizeof (*r))) == 0 ||
+ old2new(old, r) != 0) {
+ free(r);
+ delete_list(list);
+ return (0);
+ }
+ r->r_link.prev = p;
+ r->r_link.next = 0;
+ /* res_update and res_nupdate want r_glink set up like this */
+ if (do_glink) {
+ r->r_glink.prev = p;
+ r->r_glink.next = 0;
+ } else {
+ r->r_glink.prev = (void *)-1;
+ r->r_glink.next = (void *)-1;
+ }
+ if (p != 0) {
+ p->r_link.next = r;
+ if (do_glink) {
+ p->r_glink.next = r;
+ }
+ } else {
+ list = r;
+ }
+ }
+ return (list);
+}
+
+
+int
+res_mkupdate(ns_updrec *rrecp_in, uchar_t *buf, int length) {
+
+ __ISC_ns_updrec *r;
+ int ret;
+
+ if ((r = copy_list(rrecp_in, 1)) == 0)
+ return (-1);
+
+ ret = __ISC_res_mkupdate(r, buf, length);
+
+ delete_list(r);
+
+ return (ret);
+}
+
+int
+res_nmkupdate(res_state statp, ns_updrec *rrecp_in, uchar_t *buf, int length) {
+
+ __ISC_ns_updrec *r;
+ int ret;
+
+ if ((r = copy_list(rrecp_in, 1)) == 0)
+ return (-1);
+
+ ret = __ISC_res_nmkupdate(statp, r, buf, length);
+
+ delete_list(r);
+
+ return (ret);
+}
+
+
+int
+res_update(ns_updrec *rrecp_in) {
+
+ __ISC_ns_updrec *r;
+ int ret;
+
+ if ((r = copy_list(rrecp_in, 0)) == 0)
+ return (-1);
+
+ ret = __ISC_res_update(r);
+
+ delete_list(r);
+
+ return (ret);
+}
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+
+ __ISC_ns_updrec *r;
+ int ret;
+
+ if ((r = copy_list(rrecp_in, 0)) == 0)
+ return (-1);
+
+ ret = __ISC_res_nupdate(statp, r, key);
+
+ delete_list(r);
+
+ return (ret);
+}
+
+
+
+ns_updrec *
+res_mkupdrec(int section, const char *dname, uint_t class, uint_t type,
+ uint_t ttl) {
+
+ __ISC_ns_updrec *n;
+ ns_updrec *o;
+
+ n = __ISC_res_mkupdrec(section, dname, class, type, ttl);
+ if (n == 0)
+ return (0);
+
+ if ((o = calloc(1, sizeof (*o))) != 0) {
+ if (new2old(n, o) != 0) {
+ res_freeupdrec(o);
+ o = 0;
+ }
+ }
+
+ __ISC_res_freeupdrec(n);
+
+ return (o);
+}
+
+
+void
+res_freeupdrec(ns_updrec *rrecp) {
+ if (rrecp == 0)
+ return;
+ /* Note: freeing r_dp is the caller's responsibility. */
+ if (rrecp->r_dname != NULL)
+ free(rrecp->r_dname);
+ free(rrecp);
+}
diff --git a/usr/src/lib/libresolv2_joy/common/sunw/sunw_wrappers.c b/usr/src/lib/libresolv2_joy/common/sunw/sunw_wrappers.c
new file mode 100644
index 0000000000..55bbe07024
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/common/sunw/sunw_wrappers.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <port_before.h>
+#include <resolv_joy.h>
+#include <arpa/inet.h>
+#include <port_after.h>
+
+#undef p_option
+/* extern const char * isc_p_option(); */
+const char *p_option(uint_t option) {
+ return (isc_p_option((ulong_t)option));
+}
+#pragma weak __p_option = p_option
+
+#undef p_secstodate
+/* extern char * isc_p_secstodate (); */
+char *p_secstodate(uint_t secs) {
+ return (isc_p_secstodate((ulong_t)secs));
+}
+#pragma weak __p_secstodate = p_secstodate
diff --git a/usr/src/lib/libresolv2_joy/i386/Makefile b/usr/src/lib/libresolv2_joy/i386/Makefile
new file mode 100644
index 0000000000..a333224278
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libresolv2_joy/include/Makefile b/usr/src/lib/libresolv2_joy/include/Makefile
new file mode 100644
index 0000000000..8bff3c3188
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/Makefile
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../../Makefile.master
+
+HDRS= os_version.h port_ipv6.h
+TMPHDRS= new_os_version.h new_port_ipv6.h
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+
+.KEEP_STATE:
+
+all lint: $(HDRS)
+
+install: all
+
+clean:
+ $(RM) $(HDRS) $(TMPHDRS)
+
+clobber: clean
+
+# os_version.h and port_ipv6.h should be rebuilt when you change OS
+# revision. Since that's not easily expressed as a dependency, we
+# rebuild them every time.
+
+os_version.h: make_os_version FRC
+ ./make_os_version
+
+port_ipv6.h: probe_ipv6 FRC
+ CC="$(CC)" ./probe_ipv6
+
+FRC:
diff --git a/usr/src/lib/libresolv2_joy/include/arpa/port_inet.h b/usr/src/lib/libresolv2_joy/include/arpa/port_inet.h
new file mode 100644
index 0000000000..5eb1787f56
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/arpa/port_inet.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ *
+ * All rights reserved.
+ */
+
+#ifndef _ARPA_PORT_INET_H
+#define _ARPA_PORT_INET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * these are libresolv2 functions that were made local in previous versions
+ * we rename them res_* because they conflict with libnsl or libsocket
+ */
+
+#define inet_lnaof res_inet_lnaof /* libsocket */
+ulong_t inet_lnaof(struct in_addr in);
+
+#define inet_makeaddr res_inet_makeaddr /* libsocket */
+struct in_addr inet_makeaddr(ulong_t net, ulong_t host);
+
+#define inet_netof res_inet_netof /* libnsl */
+ulong_t inet_netof(struct in_addr in);
+
+#define inet_network res_inet_network /* libsocket */
+ulong_t inet_network(register const char *cp);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* _ARPA_PORT_INET_H */
diff --git a/usr/src/lib/libresolv2_joy/include/arpa/port_nameser.h b/usr/src/lib/libresolv2_joy/include/arpa/port_nameser.h
new file mode 100644
index 0000000000..b40ea0d163
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/arpa/port_nameser.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ARPA_PORT_NAMESER_H
+#define _ARPA_PORT_NAMESER_H
+
+/*
+ * ISC changed the ns_updrec structure. However, it's a public interface
+ * in Solaris, so we rename it here and wrap in sunw_updrec.c
+ */
+#define ns_updrec __ISC_ns_updrec
+
+
+/*
+ * Due to the above, the following functions need to be renamed and
+ * wrapped in sunw_updrec.c.
+ *
+ * For BIND 8.2.2, ISC removed the dynamic update functions, and the
+ * definition of the ns_updrec structure, from the public include files
+ * (<resolv.h>, <arpa/nameser.h>. However, res_update(), res_mkupdate(),
+ * and res_mkupdrec() are in the public libresolv interface in Solaris,
+ * so we can't easily remove them. Thus, ISC's new versions of res_mkupdate()
+ * etc. can't be exposed under their original names.
+ *
+ * res_nmkupdate() and res_nupdate are new. We could either change them
+ * to accept the <arpa/nameser.h> ns_updrec, or leave them unchanged and
+ * undocumented. Since ISC may change ns_updrec again, we pick the latter
+ * solution for now.
+ */
+#define res_mkupdate __ISC_res_mkupdate
+#define res_update __ISC_res_update
+#define res_mkupdrec __ISC_res_mkupdrec
+#define res_freeupdrec __ISC_res_freeupdrec
+#define res_nmkupdate __ISC_res_nmkupdate
+#define res_nupdate __ISC_res_nupdate
+
+
+#endif /* _ARPA_PORT_NAMESER_H */
diff --git a/usr/src/lib/libresolv2_joy/include/conf/sunoptions.h b/usr/src/lib/libresolv2_joy/include/conf/sunoptions.h
new file mode 100644
index 0000000000..b75ff9d878
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/conf/sunoptions.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SUNOPTIONS_H
+#define _SUNOPTIONS_H
+
+#define USELOOPBACK /* Resolver library defaults to 127.0.0.1 */
+
+/* Additions for Solaris 2 */
+
+#define SUNW_INITCHKIF /* Check if any non-loopback interface is up */
+#define SUNW_CONFCHECK /* Abort quickly if no /etc/resolv.conf or */
+ /* local named */
+#define SUNW_HOSTS_FALLBACK /* Configurable /etc/hosts fallback */
+#define SUNW_HNOK_UNDERSCORE /* Allow underscore in hostnames (libresolv) */
+#define SUNW_MT_RESOLVER /* MT hot extensions (libresolv) */
+#define SUNW_SETHERRNO /* ISC does not set h_errno in gethostbyname */
+#define SUNW_OVERRIDE_RETRY /* Allow NS switch to override res->retry */
+#define SUNW_LIBMD5 /* Use md5(3EXT) instead of internal implementation */
+
+/* If compiling an MT warm libresolv, we also need reentrancy */
+#if defined(SUNW_MT_RESOLVER) && !defined(_REENTRANT)
+#define _REENTRANT
+#endif
+
+/* End additions for Solaris 2 */
+
+#endif /* _SUNOPTIONS_H */
diff --git a/usr/src/lib/libresolv2_joy/include/config.h b/usr/src/lib/libresolv2_joy/include/config.h
new file mode 100644
index 0000000000..35fb115a0f
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/config.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/* config.h. Generated from config.h.in by configure. */
+/* #undef _SOCKADDR_LEN */
+#define HAVE_FCNTL_H 1
+/* #undef HAVE_PATHS_H */
+#define HAVE_INTTYPES_H 1
+#define HAVE_STROPTS_H 1
+/* #undef HAVE_SYS_TIMERS_H */
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_MEMORY_H 1
+/* #undef SYS_CDEFS_H */
+#define _POSIX_PTHREAD_SEMANTICS 1
+#define POSIX_GETPWUID_R 1
+#define POSIX_GETPWNAM_R 1
+#define POSIX_GETGRGID_R 1
+#define POSIX_GETGRNAM_R 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCHR 1
+/* #undef SPRINTF_CHAR */
+/* #undef VSPRINTF_CHAR */
+#define USE_SYSERROR_LIST 1
+/* #undef NEED_STRTOUL */
+/* #undef NEED_SUN4PROTOS */
+/* #undef REENABLE_SEND */
+
+#define NEED_SETGROUPENT 1
+#define NEED_GETGROUPLIST 1
+
+/* define if prototype for getgrnam_r() is required */
+/* #undef NEED_GETGRNAM_R */
+/* #undef NEED_GETGRGID_R */
+/* #undef NEED_GETGRENT_R */
+#define NEED_SETGRENT_R 1
+#define NEED_ENDGRENT_R 1
+
+#define NEED_INNETGR_R 1
+/* #undef NEED_SETNETGRENT_R */
+#define NEED_ENDNETGRENT_R 1
+
+/* #undef NEED_GETPWNAM_R */
+/* #undef NEED_GETPWUID_R */
+#define NEED_SETPWENT_R 1
+#define NEED_SETPASSENT_R 1
+#define NEED_SETPWENT_R 1
+/* #undef NEED_GETPWENT_R */
+#define NEED_ENDPWENT_R 1
+
+#define NEED_SETPASSENT 1
+
+/* #undef HAS_PW_CLASS */
+
+/* #undef ssize_t */
+/* #undef uintptr_t */
+
+/* Shut up warnings about sputaux in stdio.h on BSD/OS pre-4.1 */
+/* #undef SHUTUP_SPUTAUX */
+#ifdef SHUTUP_SPUTAUX
+struct __sFILE;
+extern __inline int __sputaux(int _c, struct __sFILE *_p);
+#endif
+#define BROKEN_IN6ADDR_INIT_MACROS 1
+#define HAVE_STRLCAT 1
+/* Shut up warnings about missing braces */
+/* #undef SHUTUP_MUTEX_INITIALIZER */
+#ifdef SHUTUP_MUTEX_INITIALIZER
+#define LIBBIND_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+#else
+#define LIBBIND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#endif
+
diff --git a/usr/src/lib/libresolv2_joy/include/err.h b/usr/src/lib/libresolv2_joy/include/err.h
new file mode 100644
index 0000000000..45992ea336
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/err.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)err.h 8.1 (Berkeley) 6/2/93
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef _ERR_H_
+#define _ERR_H_
+
+#include <sys/cdefs.h>
+#include <stdarg.h>
+
+__BEGIN_DECLS
+__dead void err __P((int, const char *, ...)) __attribute__((__volatile));
+__dead void verr __P((int, const char *, va_list))
+ __attribute__((__volatile));
+__dead void errx __P((int, const char *, ...)) __attribute__((__volatile));
+__dead void verrx __P((int, const char *, va_list))
+ __attribute__((__volatile));
+void warn __P((const char *, ...));
+void vwarn __P((const char *, va_list));
+void warnx __P((const char *, ...));
+void vwarnx __P((const char *, va_list));
+__END_DECLS
+
+#endif /* !_ERR_H_ */
diff --git a/usr/src/lib/libresolv2_joy/include/fd_setsize.h b/usr/src/lib/libresolv2_joy/include/fd_setsize.h
new file mode 100644
index 0000000000..0e21049742
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/fd_setsize.h
@@ -0,0 +1,10 @@
+#ifndef _FD_SETSIZE_H
+#define _FD_SETSIZE_H
+
+/*%
+ * If you need a bigger FD_SETSIZE, this is NOT the place to set it.
+ * This file is a fallback for BIND ports which don't specify their own.
+ */
+
+#endif /* _FD_SETSIZE_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/hesiod.h b/usr/src/lib/libresolv2_joy/include/hesiod.h
new file mode 100644
index 0000000000..d64c0c5e80
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/hesiod.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file
+ * \brief
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * $Id: hesiod.h,v 1.4 2005/04/27 04:56:14 sra Exp $
+ */
+
+#ifndef _HESIOD_H_INCLUDED
+#define _HESIOD_H_INCLUDED
+
+int hesiod_init __P((void **));
+void hesiod_end __P((void *));
+char * hesiod_to_bind __P((void *, const char *, const char *));
+char ** hesiod_resolve __P((void *, const char *, const char *));
+void hesiod_free_list __P((void *, char **));
+struct __res_state * __hesiod_res_get __P((void *));
+void __hesiod_res_set __P((void *, struct __res_state *,
+ void (*)(void *)));
+
+#endif /*_HESIOD_H_INCLUDED*/
diff --git a/usr/src/lib/libresolv2_joy/include/irp.h b/usr/src/lib/libresolv2_joy/include/irp.h
new file mode 100644
index 0000000000..1290bd068f
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/irp.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irp.h,v 1.4 2005/04/27 04:56:15 sra Exp $
+ */
+
+#ifndef _IRP_H_INCLUDED
+#define _IRP_H_INCLUDED
+
+/*! \file */
+
+#define IRPD_TIMEOUT 30 /*%< seconds */
+#define IRPD_MAXSESS 50 /*%< number of simultaneous sessions. */
+#define IRPD_PORT 6660 /*%< 10 times the number of the beast. */
+#define IRPD_PATH "/var/run/irpd" /*%< af_unix socket path */
+
+/* If sets the environment variable IRPDSERVER to an IP address
+ (e.g. "192.5.5.1"), then that's the host the client expects irpd to be
+ running on. */
+#define IRPD_HOST_ENV "IRPDSERVER"
+
+/* Protocol response codes. */
+#define IRPD_WELCOME_CODE 200
+#define IRPD_NOT_WELCOME_CODE 500
+
+#define IRPD_GETHOST_ERROR 510
+#define IRPD_GETHOST_NONE 210
+#define IRPD_GETHOST_OK 211
+#define IRPD_GETHOST_SETOK 212
+
+#define IRPD_GETNET_ERROR 520
+#define IRPD_GETNET_NONE 220
+#define IRPD_GETNET_OK 221
+#define IRPD_GETNET_SETOK 222
+
+#define IRPD_GETUSER_ERROR 530
+#define IRPD_GETUSER_NONE 230
+#define IRPD_GETUSER_OK 231
+#define IRPD_GETUSER_SETOK 232
+
+#define IRPD_GETGROUP_ERROR 540
+#define IRPD_GETGROUP_NONE 240
+#define IRPD_GETGROUP_OK 241
+#define IRPD_GETGROUP_SETOK 242
+
+#define IRPD_GETSERVICE_ERROR 550
+#define IRPD_GETSERVICE_NONE 250
+#define IRPD_GETSERVICE_OK 251
+#define IRPD_GETSERVICE_SETOK 252
+
+#define IRPD_GETPROTO_ERROR 560
+#define IRPD_GETPROTO_NONE 260
+#define IRPD_GETPROTO_OK 261
+#define IRPD_GETPROTO_SETOK 262
+
+#define IRPD_GETNETGR_ERROR 570
+#define IRPD_GETNETGR_NONE 270
+#define IRPD_GETNETGR_OK 271
+#define IRPD_GETNETGR_NOMORE 272
+#define IRPD_GETNETGR_MATCHES 273
+#define IRPD_GETNETGR_NOMATCH 274
+#define IRPD_GETNETGR_SETOK 275
+#define IRPD_GETNETGR_SETERR 276
+
+#define irs_irp_read_body __irs_irp_read_body
+#define irs_irp_read_response __irs_irp_read_response
+#define irs_irp_disconnect __irs_irp_disconnect
+#define irs_irp_connect __irs_irp_connect
+#define irs_irp_connection_setup __irs_irp_connection_setup
+#define irs_irp_send_command __irs_irp_send_command
+
+struct irp_p;
+
+char *irs_irp_read_body(struct irp_p *, size_t *);
+int irs_irp_read_response(struct irp_p *, char *, size_t);
+void irs_irp_disconnect(struct irp_p *);
+int irs_irp_connect(struct irp_p *);
+int irs_irp_is_connected(struct irp_p *);
+int irs_irp_connection_setup(struct irp_p *, int *);
+#ifdef __GNUC__
+int irs_irp_send_command(struct irp_p *, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+#else
+int irs_irp_send_command(struct irp_p *, const char *, ...);
+#endif
+int irs_irp_get_full_response(struct irp_p *, int *, char *, size_t,
+ char **, size_t *);
+int irs_irp_read_line(struct irp_p *, char *, int);
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/irs.h b/usr/src/lib/libresolv2_joy/include/irs.h
new file mode 100644
index 0000000000..386e3cb3f6
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/irs.h
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irs.h,v 1.5 2005/04/27 04:56:15 sra Exp $
+ */
+
+#ifndef _IRS_H_INCLUDED
+#define _IRS_H_INCLUDED
+
+/*! \file */
+
+#include <sys/types.h>
+
+#include <arpa/nameser.h>
+
+#include <grp.h>
+#include <netdb.h>
+#include <resolv_joy.h>
+#include <pwd.h>
+
+/*%
+ * This is the group map class.
+ */
+struct irs_gr {
+ void * private;
+ void (*close) __P((struct irs_gr *));
+ struct group * (*next) __P((struct irs_gr *));
+ struct group * (*byname) __P((struct irs_gr *, const char *));
+ struct group * (*bygid) __P((struct irs_gr *, gid_t));
+ int (*list) __P((struct irs_gr *, const char *,
+ gid_t, gid_t *, int *));
+ void (*rewind) __P((struct irs_gr *));
+ void (*minimize) __P((struct irs_gr *));
+ struct __res_state * (*res_get) __P((struct irs_gr *));
+ void (*res_set) __P((struct irs_gr *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the password map class.
+ */
+struct irs_pw {
+ void * private;
+ void (*close) __P((struct irs_pw *));
+ struct passwd * (*next) __P((struct irs_pw *));
+ struct passwd * (*byname) __P((struct irs_pw *, const char *));
+ struct passwd * (*byuid) __P((struct irs_pw *, uid_t));
+ void (*rewind) __P((struct irs_pw *));
+ void (*minimize) __P((struct irs_pw *));
+ struct __res_state * (*res_get) __P((struct irs_pw *));
+ void (*res_set) __P((struct irs_pw *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the service map class.
+ */
+struct irs_sv {
+ void * private;
+ void (*close) __P((struct irs_sv *));
+ struct servent *(*byname) __P((struct irs_sv *,
+ const char *, const char *));
+ struct servent *(*byport) __P((struct irs_sv *, int, const char *));
+ struct servent *(*next) __P((struct irs_sv *));
+ void (*rewind) __P((struct irs_sv *));
+ void (*minimize) __P((struct irs_sv *));
+ struct __res_state * (*res_get) __P((struct irs_sv *));
+ void (*res_set) __P((struct irs_sv *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the protocols map class.
+ */
+struct irs_pr {
+ void * private;
+ void (*close) __P((struct irs_pr *));
+ struct protoent *(*byname) __P((struct irs_pr *, const char *));
+ struct protoent *(*bynumber) __P((struct irs_pr *, int));
+ struct protoent *(*next) __P((struct irs_pr *));
+ void (*rewind) __P((struct irs_pr *));
+ void (*minimize) __P((struct irs_pr *));
+ struct __res_state * (*res_get) __P((struct irs_pr *));
+ void (*res_set) __P((struct irs_pr *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the hosts map class.
+ */
+struct irs_ho {
+ void * private;
+ void (*close) __P((struct irs_ho *));
+ struct hostent *(*byname) __P((struct irs_ho *, const char *));
+ struct hostent *(*byname2) __P((struct irs_ho *, const char *, int));
+ struct hostent *(*byaddr) __P((struct irs_ho *,
+ const void *, int, int));
+ struct hostent *(*next) __P((struct irs_ho *));
+ void (*rewind) __P((struct irs_ho *));
+ void (*minimize) __P((struct irs_ho *));
+ struct __res_state * (*res_get) __P((struct irs_ho *));
+ void (*res_set) __P((struct irs_ho *, res_state,
+ void (*)(void *)));
+ struct addrinfo *(*addrinfo) __P((struct irs_ho *, const char *,
+ const struct addrinfo *));
+};
+
+/*%
+ * This is the networks map class.
+ */
+struct irs_nw {
+ void * private;
+ void (*close) __P((struct irs_nw *));
+ struct nwent * (*byname) __P((struct irs_nw *, const char *, int));
+ struct nwent * (*byaddr) __P((struct irs_nw *, void *, int, int));
+ struct nwent * (*next) __P((struct irs_nw *));
+ void (*rewind) __P((struct irs_nw *));
+ void (*minimize) __P((struct irs_nw *));
+ struct __res_state * (*res_get) __P((struct irs_nw *));
+ void (*res_set) __P((struct irs_nw *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is the netgroups map class.
+ */
+struct irs_ng {
+ void * private;
+ void (*close) __P((struct irs_ng *));
+ int (*next) __P((struct irs_ng *, const char **,
+ const char **, const char **));
+ int (*test) __P((struct irs_ng *, const char *,
+ const char *, const char *,
+ const char *));
+ void (*rewind) __P((struct irs_ng *, const char *));
+ void (*minimize) __P((struct irs_ng *));
+};
+
+/*%
+ * This is the generic map class, which copies the front of all others.
+ */
+struct irs_map {
+ void * private;
+ void (*close) __P((void *));
+};
+
+/*%
+ * This is the accessor class. It contains pointers to all of the
+ * initializers for the map classes for a particular accessor.
+ */
+struct irs_acc {
+ void * private;
+ void (*close) __P((struct irs_acc *));
+ struct irs_gr * (*gr_map) __P((struct irs_acc *));
+ struct irs_pw * (*pw_map) __P((struct irs_acc *));
+ struct irs_sv * (*sv_map) __P((struct irs_acc *));
+ struct irs_pr * (*pr_map) __P((struct irs_acc *));
+ struct irs_ho * (*ho_map) __P((struct irs_acc *));
+ struct irs_nw * (*nw_map) __P((struct irs_acc *));
+ struct irs_ng * (*ng_map) __P((struct irs_acc *));
+ struct __res_state * (*res_get) __P((struct irs_acc *));
+ void (*res_set) __P((struct irs_acc *, res_state,
+ void (*)(void *)));
+};
+
+/*%
+ * This is because the official definition of "struct netent" has no
+ * concept of CIDR even though it allows variant address families (on
+ * output but not input). The compatibility stubs convert the structs
+ * below into "struct netent"'s.
+ */
+struct nwent {
+ char *n_name; /*%< official name of net */
+ char **n_aliases; /*%< alias list */
+ int n_addrtype; /*%< net address type */
+ void *n_addr; /*%< network address */
+ int n_length; /*%< address length, in bits */
+};
+
+/*%
+ * Hide external function names from POSIX.
+ */
+#define irs_gen_acc __irs_gen_acc
+#define irs_lcl_acc __irs_lcl_acc
+#define irs_dns_acc __irs_dns_acc
+#define irs_nis_acc __irs_nis_acc
+#define irs_irp_acc __irs_irp_acc
+#define irs_destroy __irs_destroy
+#define irs_dns_gr __irs_dns_gr
+#define irs_dns_ho __irs_dns_ho
+#define irs_dns_nw __irs_dns_nw
+#define irs_dns_pr __irs_dns_pr
+#define irs_dns_pw __irs_dns_pw
+#define irs_dns_sv __irs_dns_sv
+#define irs_gen_gr __irs_gen_gr
+#define irs_gen_ho __irs_gen_ho
+#define irs_gen_ng __irs_gen_ng
+#define irs_gen_nw __irs_gen_nw
+#define irs_gen_pr __irs_gen_pr
+#define irs_gen_pw __irs_gen_pw
+#define irs_gen_sv __irs_gen_sv
+#define irs_irp_get_full_response __irs_irp_get_full_response
+#define irs_irp_gr __irs_irp_gr
+#define irs_irp_ho __irs_irp_ho
+#define irs_irp_is_connected __irs_irp_is_connected
+#define irs_irp_ng __irs_irp_ng
+#define irs_irp_nw __irs_irp_nw
+#define irs_irp_pr __irs_irp_pr
+#define irs_irp_pw __irs_irp_pw
+#define irs_irp_read_line __irs_irp_read_line
+#define irs_irp_sv __irs_irp_sv
+#define irs_lcl_gr __irs_lcl_gr
+#define irs_lcl_ho __irs_lcl_ho
+#define irs_lcl_ng __irs_lcl_ng
+#define irs_lcl_nw __irs_lcl_nw
+#define irs_lcl_pr __irs_lcl_pr
+#define irs_lcl_pw __irs_lcl_pw
+#define irs_lcl_sv __irs_lcl_sv
+#define irs_nis_gr __irs_nis_gr
+#define irs_nis_ho __irs_nis_ho
+#define irs_nis_ng __irs_nis_ng
+#define irs_nis_nw __irs_nis_nw
+#define irs_nis_pr __irs_nis_pr
+#define irs_nis_pw __irs_nis_pw
+#define irs_nis_sv __irs_nis_sv
+#define net_data_create __net_data_create
+#define net_data_destroy __net_data_destroy
+#define net_data_minimize __net_data_minimize
+
+/*%
+ * Externs.
+ */
+extern struct irs_acc * irs_gen_acc __P((const char *, const char *));
+extern struct irs_acc * irs_lcl_acc __P((const char *));
+extern struct irs_acc * irs_dns_acc __P((const char *));
+extern struct irs_acc * irs_nis_acc __P((const char *));
+extern struct irs_acc * irs_irp_acc __P((const char *));
+
+extern void irs_destroy __P((void));
+
+/*%
+ * These forward declarations are for the semi-private functions in
+ * the get*.c files. Each of these funcs implements the real get*
+ * functionality and the standard versions are just wrappers that
+ * call these. Apart from the wrappers, only irpd is expected to
+ * call these directly, hence these decls are put here and not in
+ * the /usr/include replacements.
+ */
+
+struct net_data; /*%< forward */
+/*
+ * net_data_create gets a singleton net_data object. net_data_init
+ * creates as many net_data objects as times it is called. Clients using
+ * the default interface will use net_data_create by default. Servers will
+ * probably want net_data_init (one call per client)
+ */
+struct net_data *net_data_create __P((const char *));
+struct net_data *net_data_init __P((const char *));
+void net_data_destroy __P((void *));
+
+extern struct group *getgrent_p __P((struct net_data *));
+extern struct group *getgrnam_p __P((const char *, struct net_data *));
+extern struct group *getgrgid_p __P((gid_t, struct net_data *));
+extern int setgroupent_p __P((int, struct net_data *));
+extern void endgrent_p __P((struct net_data *));
+extern int getgrouplist_p __P((const char *, gid_t, gid_t *, int *,
+ struct net_data *));
+
+#ifdef SETGRENT_VOID
+extern void setgrent_p __P((struct net_data *));
+#else
+extern int setgrent_p __P((struct net_data *));
+#endif
+
+extern struct hostent *gethostbyname_p __P((const char *,
+ struct net_data *));
+extern struct hostent *gethostbyname2_p __P((const char *, int,
+ struct net_data *));
+extern struct hostent *gethostbyaddr_p __P((const char *, int, int,
+ struct net_data *));
+extern struct hostent *gethostent_p __P((struct net_data *));
+extern void sethostent_p __P((int, struct net_data *));
+extern void endhostent_p __P((struct net_data *));
+extern struct hostent *getipnodebyname_p __P((const char *, int, int, int *,
+ struct net_data *));
+extern struct hostent *getipnodebyaddr_p __P((const void *, size_t,
+ int, int *, struct net_data *));
+
+extern struct netent *getnetent_p __P((struct net_data *));
+extern struct netent *getnetbyname_p __P((const char *, struct net_data *));
+extern struct netent *getnetbyaddr_p __P((unsigned long, int,
+ struct net_data *));
+extern void setnetent_p __P((int, struct net_data *));
+extern void endnetent_p __P((struct net_data *));
+
+extern void setnetgrent_p __P((const char *, struct net_data *));
+extern void endnetgrent_p __P((struct net_data *));
+extern int innetgr_p __P((const char *, const char *, const char *,
+ const char *, struct net_data *));
+extern int getnetgrent_p __P((const char **, const char **,
+ const char **, struct net_data *));
+
+extern struct protoent *getprotoent_p __P((struct net_data *));
+extern struct protoent *getprotobyname_p __P((const char *,
+ struct net_data *));
+extern struct protoent *getprotobynumber_p __P((int, struct net_data *));
+extern void setprotoent_p __P((int, struct net_data *));
+extern void endprotoent_p __P((struct net_data *));
+
+
+extern struct passwd *getpwent_p __P((struct net_data *));
+extern struct passwd *getpwnam_p __P((const char *, struct net_data *));
+extern struct passwd *getpwuid_p __P((uid_t, struct net_data *));
+extern int setpassent_p __P((int, struct net_data *));
+extern void endpwent_p __P((struct net_data *));
+
+#ifdef SETPWENT_VOID
+extern void setpwent_p __P((struct net_data *));
+#else
+extern int setpwent_p __P((struct net_data *));
+#endif
+
+extern struct servent *getservent_p __P((struct net_data *));
+extern struct servent *getservbyname_p __P((const char *, const char *,
+ struct net_data *));
+extern struct servent *getservbyport_p __P((int, const char *,
+ struct net_data *));
+extern void setservent_p __P((int, struct net_data *));
+extern void endservent_p __P((struct net_data *));
+
+#endif /*_IRS_H_INCLUDED*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/assertions.h b/usr/src/lib/libresolv2_joy/include/isc/assertions.h
new file mode 100644
index 0000000000..68925e73b3
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/assertions.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1997-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: assertions.h,v 1.5 2008/11/14 02:36:51 marka Exp $
+ */
+
+#ifndef ASSERTIONS_H
+#define ASSERTIONS_H 1
+
+typedef enum {
+ assert_require, assert_ensure, assert_insist, assert_invariant
+} assertion_type;
+
+typedef void (*assertion_failure_callback)(const char *, int, assertion_type,
+ const char *, int);
+
+/* coverity[+kill] */
+extern assertion_failure_callback __assertion_failed;
+void set_assertion_failure_callback(assertion_failure_callback f);
+const char *assertion_type_to_text(assertion_type type);
+
+#if defined(CHECK_ALL) || defined(__COVERITY__)
+#define CHECK_REQUIRE 1
+#define CHECK_ENSURE 1
+#define CHECK_INSIST 1
+#define CHECK_INVARIANT 1
+#endif
+
+#if defined(CHECK_NONE) && !defined(__COVERITY__)
+#define CHECK_REQUIRE 0
+#define CHECK_ENSURE 0
+#define CHECK_INSIST 0
+#define CHECK_INVARIANT 0
+#endif
+
+#ifndef CHECK_REQUIRE
+#define CHECK_REQUIRE 1
+#endif
+
+#ifndef CHECK_ENSURE
+#define CHECK_ENSURE 1
+#endif
+
+#ifndef CHECK_INSIST
+#define CHECK_INSIST 1
+#endif
+
+#ifndef CHECK_INVARIANT
+#define CHECK_INVARIANT 1
+#endif
+
+#if CHECK_REQUIRE != 0
+#define REQUIRE(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_require, \
+ #cond, 0), 0)))
+#define REQUIRE_ERR(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_require, \
+ #cond, 1), 0)))
+#else
+#define REQUIRE(cond) ((void) (cond))
+#define REQUIRE_ERR(cond) ((void) (cond))
+#endif /* CHECK_REQUIRE */
+
+#if CHECK_ENSURE != 0
+#define ENSURE(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \
+ #cond, 0), 0)))
+#define ENSURE_ERR(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \
+ #cond, 1), 0)))
+#else
+#define ENSURE(cond) ((void) (cond))
+#define ENSURE_ERR(cond) ((void) (cond))
+#endif /* CHECK_ENSURE */
+
+#if CHECK_INSIST != 0
+#define INSIST(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \
+ #cond, 0), 0)))
+#define INSIST_ERR(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \
+ #cond, 1), 0)))
+#else
+#define INSIST(cond) ((void) (cond))
+#define INSIST_ERR(cond) ((void) (cond))
+#endif /* CHECK_INSIST */
+
+#if CHECK_INVARIANT != 0
+#define INVARIANT(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \
+ #cond, 0), 0)))
+#define INVARIANT_ERR(cond) \
+ ((void) ((cond) || \
+ ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \
+ #cond, 1), 0)))
+#else
+#define INVARIANT(cond) ((void) (cond))
+#define INVARIANT_ERR(cond) ((void) (cond))
+#endif /* CHECK_INVARIANT */
+#endif /* ASSERTIONS_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/ctl.h b/usr/src/lib/libresolv2_joy/include/isc/ctl.h
new file mode 100644
index 0000000000..e2ba20201d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/ctl.h
@@ -0,0 +1,112 @@
+#ifndef ISC_CTL_H
+#define ISC_CTL_H
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1998,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: ctl.h,v 1.5 2005/04/27 04:56:17 sra Exp $
+ */
+
+/*! \file */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <isc/eventlib.h>
+
+/* Macros. */
+
+#define CTL_MORE 0x0001 /*%< More will be / should be sent. */
+#define CTL_EXIT 0x0002 /*%< Close connection after this. */
+#define CTL_DATA 0x0004 /*%< Go into / this is DATA mode. */
+/* Types. */
+
+struct ctl_cctx;
+struct ctl_sctx;
+struct ctl_sess;
+struct ctl_verb;
+
+enum ctl_severity { ctl_debug, ctl_warning, ctl_error };
+
+typedef void (*ctl_logfunc)(enum ctl_severity, const char *, ...);
+
+typedef void (*ctl_verbfunc)(struct ctl_sctx *, struct ctl_sess *,
+ const struct ctl_verb *, const char *,
+ u_int, const void *, void *);
+
+typedef void (*ctl_srvrdone)(struct ctl_sctx *, struct ctl_sess *, void *);
+
+typedef void (*ctl_clntdone)(struct ctl_cctx *, void *, const char *, u_int);
+
+struct ctl_verb {
+ const char * name;
+ ctl_verbfunc func;
+ const char * help;
+};
+
+/* General symbols. */
+
+#define ctl_logger __ctl_logger
+
+#ifdef __GNUC__
+void ctl_logger(enum ctl_severity, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+#else
+void ctl_logger(enum ctl_severity, const char *, ...);
+#endif
+
+/* Client symbols. */
+
+#define ctl_client __ctl_client
+#define ctl_endclient __ctl_endclient
+#define ctl_command __ctl_command
+
+struct ctl_cctx * ctl_client(evContext, const struct sockaddr *, size_t,
+ const struct sockaddr *, size_t,
+ ctl_clntdone, void *,
+ u_int, ctl_logfunc);
+void ctl_endclient(struct ctl_cctx *);
+int ctl_command(struct ctl_cctx *, const char *, size_t,
+ ctl_clntdone, void *);
+
+/* Server symbols. */
+
+#define ctl_server __ctl_server
+#define ctl_endserver __ctl_endserver
+#define ctl_response __ctl_response
+#define ctl_sendhelp __ctl_sendhelp
+#define ctl_getcsctx __ctl_getcsctx
+#define ctl_setcsctx __ctl_setcsctx
+
+struct ctl_sctx * ctl_server(evContext, const struct sockaddr *, size_t,
+ const struct ctl_verb *,
+ u_int, u_int,
+ u_int, int, int,
+ ctl_logfunc, void *);
+void ctl_endserver(struct ctl_sctx *);
+void ctl_response(struct ctl_sess *, u_int,
+ const char *, u_int, const void *,
+ ctl_srvrdone, void *,
+ const char *, size_t);
+void ctl_sendhelp(struct ctl_sess *, u_int);
+void * ctl_getcsctx(struct ctl_sess *);
+void * ctl_setcsctx(struct ctl_sess *, void *);
+
+#endif /*ISC_CTL_H*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/dst.h b/usr/src/lib/libresolv2_joy/include/isc/dst.h
new file mode 100644
index 0000000000..90a9e67468
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/dst.h
@@ -0,0 +1,168 @@
+#ifndef DST_H
+#define DST_H
+
+#ifndef HAS_DST_KEY
+typedef struct dst_key {
+ char *dk_key_name; /*%< name of the key */
+ int dk_key_size; /*%< this is the size of the key in bits */
+ int dk_proto; /*%< what protocols this key can be used for */
+ int dk_alg; /*%< algorithm number from key record */
+ u_int32_t dk_flags; /*%< and the flags of the public key */
+ u_int16_t dk_id; /*%< identifier of the key */
+} DST_KEY;
+#endif /* HAS_DST_KEY */
+/*
+ * do not taint namespace
+ */
+#define dst_bsafe_init __dst_bsafe_init
+#define dst_buffer_to_key __dst_buffer_to_key
+#define dst_check_algorithm __dst_check_algorithm
+#define dst_compare_keys __dst_compare_keys
+#define dst_cylink_init __dst_cylink_init
+#define dst_dnskey_to_key __dst_dnskey_to_key
+#define dst_eay_dss_init __dst_eay_dss_init
+#define dst_free_key __dst_free_key
+#define dst_generate_key __dst_generate_key
+#define dst_hmac_md5_init __dst_hmac_md5_init
+#define dst_init __dst_init
+#define dst_key_to_buffer __dst_key_to_buffer
+#define dst_key_to_dnskey __dst_key_to_dnskey
+#define dst_read_key __dst_read_key
+#define dst_rsaref_init __dst_rsaref_init
+#define dst_s_build_filename __dst_s_build_filename
+#define dst_s_calculate_bits __dst_s_calculate_bits
+#define dst_s_conv_bignum_b64_to_u8 __dst_s_conv_bignum_b64_to_u8
+#define dst_s_conv_bignum_u8_to_b64 __dst_s_conv_bignum_u8_to_b64
+#define dst_s_dns_key_id __dst_s_dns_key_id
+#define dst_s_dump __dst_s_dump
+#define dst_s_filename_length __dst_s_filename_length
+#define dst_s_fopen __dst_s_fopen
+#define dst_s_get_int16 __dst_s_get_int16
+#define dst_s_get_int32 __dst_s_get_int32
+#define dst_s_id_calc __dst_s_id_calc
+#define dst_s_put_int16 __dst_s_put_int16
+#define dst_s_put_int32 __dst_s_put_int32
+#define dst_s_quick_random __dst_s_quick_random
+#define dst_s_quick_random_set __dst_s_quick_random_set
+#define dst_s_random __dst_s_random
+#define dst_s_semi_random __dst_s_semi_random
+#define dst_s_verify_str __dst_s_verify_str
+#define dst_sig_size __dst_sig_size
+#define dst_sign_data __dst_sign_data
+#define dst_verify_data __dst_verify_data
+#define dst_write_key __dst_write_key
+
+/*
+ * DST Crypto API defintions
+ */
+void dst_init(void);
+int dst_check_algorithm(const int);
+
+
+int dst_sign_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *, /*!< the key to use */
+ void **, /*!< pointer to state structure */
+ const u_char *, /*!< data to be signed */
+ const int, /*!< length of input data */
+ u_char *, /*!< buffer to write signature to */
+ const int); /*!< size of output buffer */
+int dst_verify_data(const int, /*!< specifies INIT/UPDATE/FINAL/ALL */
+ DST_KEY *, /*!< the key to use */
+ void **, /*!< pointer to state structure */
+ const u_char *, /*!< data to be verified */
+ const int, /*!< length of input data */
+ const u_char *, /*!< buffer containing signature */
+ const int); /*!< length of signature */
+DST_KEY *dst_read_key(const char *, /*!< name of key */
+ const u_int16_t, /*!< key tag identifier */
+ const int, /*!< key algorithm */
+ const int); /*!< Private/PublicKey wanted */
+int dst_write_key(const DST_KEY *, /*!< key to write out */
+ const int); /*!< Public/Private */
+DST_KEY *dst_dnskey_to_key(const char *, /*!< KEY record name */
+ const u_char *, /*!< KEY RDATA */
+ const int); /*!< size of input buffer */
+int dst_key_to_dnskey(const DST_KEY *, /*!< key to translate */
+ u_char *, /*!< output buffer */
+ const int); /*!< size of out_storage */
+DST_KEY *dst_buffer_to_key(const char *, /*!< name of the key */
+ const int, /*!< algorithm */
+ const int, /*!< dns flags */
+ const int, /*!< dns protocol */
+ const u_char *, /*!< key in dns wire fmt */
+ const int); /*!< size of key */
+int dst_key_to_buffer(DST_KEY *, u_char *, int);
+
+DST_KEY *dst_generate_key(const char *, /*!< name of new key */
+ const int, /*!< key algorithm to generate */
+ const int, /*!< size of new key */
+ const int, /*!< alg dependent parameter */
+ const int, /*!< key DNS flags */
+ const int); /*!< key DNS protocol */
+DST_KEY *dst_free_key(DST_KEY *);
+int dst_compare_keys(const DST_KEY *, const DST_KEY *);
+
+int dst_sig_size(DST_KEY *);
+
+
+/* support for dns key tags/ids */
+u_int16_t dst_s_dns_key_id(const u_char *, const int);
+u_int16_t dst_s_id_calc(const u_char *, const int);
+
+/* Used by callers as well as by the library. */
+#define RAW_KEY_SIZE 8192 /*%< large enough to store any key */
+/* DST_API control flags */
+/* These are used used in functions dst_sign_data and dst_verify_data */
+#define SIG_MODE_INIT 1 /*%< initialize digest */
+#define SIG_MODE_UPDATE 2 /*%< add data to digest */
+#define SIG_MODE_FINAL 4 /*%< generate/verify signature */
+#define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL)
+
+/* Flags for dst_read_private_key() */
+#define DST_FORCE_READ 0x1000000
+#define DST_CAN_SIGN 0x010F
+#define DST_NO_AUTHEN 0x8000
+#define DST_EXTEND_FLAG 0x1000
+#define DST_STANDARD 0
+#define DST_PRIVATE 0x2000000
+#define DST_PUBLIC 0x4000000
+#define DST_RAND_SEMI 1
+#define DST_RAND_STD 2
+#define DST_RAND_KEY 3
+#define DST_RAND_DSS 4
+
+
+/* DST algorithm codes */
+#define KEY_RSA 1
+#define KEY_DH 2
+#define KEY_DSA 3
+#define KEY_PRIVATE 254
+#define KEY_EXPAND 255
+#define KEY_HMAC_MD5 157
+#define KEY_HMAC_SHA1 158
+#define UNKNOWN_KEYALG 0
+#define DST_MAX_ALGS KEY_HMAC_SHA1
+
+/* DST constants to locations in KEY record changes in new KEY record */
+#define DST_FLAGS_SIZE 2
+#define DST_KEY_PROT 2
+#define DST_KEY_ALG 3
+#define DST_EXT_FLAG 4
+#define DST_KEY_START 4
+
+#ifndef SIGN_F_NOKEY
+#define SIGN_F_NOKEY 0xC000
+#endif
+
+/* error codes from dst routines */
+#define SIGN_INIT_FAILURE (-23)
+#define SIGN_UPDATE_FAILURE (-24)
+#define SIGN_FINAL_FAILURE (-25)
+#define VERIFY_INIT_FAILURE (-26)
+#define VERIFY_UPDATE_FAILURE (-27)
+#define VERIFY_FINAL_FAILURE (-28)
+#define MISSING_KEY_OR_SIGNATURE (-30)
+#define UNSUPPORTED_KEYALG (-31)
+
+#endif /* DST_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/eventlib.h b/usr/src/lib/libresolv2_joy/include/isc/eventlib.h
new file mode 100644
index 0000000000..a4cfdf9092
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/eventlib.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1995-1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* eventlib.h - exported interfaces for eventlib
+ * vix 09sep95 [initial]
+ *
+ * $Id: eventlib.h,v 1.7 2008/11/14 02:36:51 marka Exp $
+ */
+
+#ifndef _EVENTLIB_H
+#define _EVENTLIB_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include <isc/platform.h>
+
+#ifndef __P
+# define __EVENTLIB_P_DEFINED
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/* In the absence of branded types... */
+typedef struct { void *opaque; } evConnID;
+typedef struct { void *opaque; } evFileID;
+typedef struct { void *opaque; } evStreamID;
+typedef struct { void *opaque; } evTimerID;
+typedef struct { void *opaque; } evWaitID;
+typedef struct { void *opaque; } evContext;
+typedef struct { void *opaque; } evEvent;
+
+#define evInitID(id) ((id)->opaque = NULL)
+#define evTestID(id) ((id).opaque != NULL)
+
+typedef void (*evConnFunc)__P((evContext, void *, int, const void *, int,
+ const void *, int));
+typedef void (*evFileFunc)__P((evContext, void *, int, int));
+typedef void (*evStreamFunc)__P((evContext, void *, int, int));
+typedef void (*evTimerFunc)__P((evContext, void *,
+ struct timespec, struct timespec));
+typedef void (*evWaitFunc)__P((evContext, void *, const void *));
+
+typedef struct { unsigned char mask[256/8]; } evByteMask;
+#define EV_BYTEMASK_BYTE(b) ((b) / 8)
+#define EV_BYTEMASK_MASK(b) (1 << ((b) % 8))
+#define EV_BYTEMASK_SET(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] |= EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_CLR(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] &= ~EV_BYTEMASK_MASK(b))
+#define EV_BYTEMASK_TST(bm, b) \
+ ((bm).mask[EV_BYTEMASK_BYTE(b)] & EV_BYTEMASK_MASK(b))
+
+#define EV_POLL 1
+#define EV_WAIT 2
+#define EV_NULL 4
+
+#define EV_READ 1
+#define EV_WRITE 2
+#define EV_EXCEPT 4
+
+#define EV_WASNONBLOCKING 8 /* Internal library use. */
+
+/* eventlib.c */
+#define evCreate __evCreate
+#define evSetDebug __evSetDebug
+#define evDestroy __evDestroy
+#define evGetNext __evGetNext
+#define evDispatch __evDispatch
+#define evDrop __evDrop
+#define evMainLoop __evMainLoop
+#define evHighestFD __evHighestFD
+#define evGetOption __evGetOption
+#define evSetOption __evSetOption
+
+int evCreate __P((evContext *));
+void evSetDebug __P((evContext, int, FILE *));
+int evDestroy __P((evContext));
+int evGetNext __P((evContext, evEvent *, int));
+int evDispatch __P((evContext, evEvent));
+void evDrop __P((evContext, evEvent));
+int evMainLoop __P((evContext));
+int evHighestFD __P((evContext));
+int evGetOption __P((evContext *, const char *, int *));
+int evSetOption __P((evContext *, const char *, int));
+
+/* ev_connects.c */
+#define evListen __evListen
+#define evConnect __evConnect
+#define evCancelConn __evCancelConn
+#define evHold __evHold
+#define evUnhold __evUnhold
+#define evTryAccept __evTryAccept
+
+int evListen __P((evContext, int, int, evConnFunc, void *, evConnID *));
+int evConnect __P((evContext, int, const void *, int,
+ evConnFunc, void *, evConnID *));
+int evCancelConn __P((evContext, evConnID));
+int evHold __P((evContext, evConnID));
+int evUnhold __P((evContext, evConnID));
+int evTryAccept __P((evContext, evConnID, int *));
+
+/* ev_files.c */
+#define evSelectFD __evSelectFD
+#define evDeselectFD __evDeselectFD
+
+int evSelectFD __P((evContext, int, int, evFileFunc, void *, evFileID *));
+int evDeselectFD __P((evContext, evFileID));
+
+/* ev_streams.c */
+#define evConsIovec __evConsIovec
+#define evWrite __evWrite
+#define evRead __evRead
+#define evTimeRW __evTimeRW
+#define evUntimeRW __evUntimeRW
+#define evCancelRW __evCancelRW
+
+struct iovec evConsIovec __P((void *, size_t));
+int evWrite __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evRead __P((evContext, int, const struct iovec *, int,
+ evStreamFunc func, void *, evStreamID *));
+int evTimeRW __P((evContext, evStreamID, evTimerID timer));
+int evUntimeRW __P((evContext, evStreamID));
+int evCancelRW __P((evContext, evStreamID));
+
+/* ev_timers.c */
+#define evConsTime __evConsTime
+#define evAddTime __evAddTime
+#define evSubTime __evSubTime
+#define evCmpTime __evCmpTime
+#define evTimeSpec __evTimeSpec
+#define evTimeVal __evTimeVal
+
+#define evNowTime __evNowTime
+#define evUTCTime __evUTCTime
+#define evLastEventTime __evLastEventTime
+#define evSetTimer __evSetTimer
+#define evClearTimer __evClearTimer
+#define evConfigTimer __evConfigTimer
+#define evResetTimer __evResetTimer
+#define evSetIdleTimer __evSetIdleTimer
+#define evClearIdleTimer __evClearIdleTimer
+#define evResetIdleTimer __evResetIdleTimer
+#define evTouchIdleTimer __evTouchIdleTimer
+
+struct timespec evConsTime __P((time_t sec, long nsec));
+struct timespec evAddTime __P((struct timespec, struct timespec));
+struct timespec evSubTime __P((struct timespec, struct timespec));
+struct timespec evNowTime __P((void));
+struct timespec evUTCTime __P((void));
+struct timespec evLastEventTime __P((evContext));
+struct timespec evTimeSpec __P((struct timeval));
+struct timeval evTimeVal __P((struct timespec));
+int evCmpTime __P((struct timespec, struct timespec));
+int evSetTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ struct timespec, evTimerID *));
+int evClearTimer __P((evContext, evTimerID));
+int evConfigTimer __P((evContext, evTimerID, const char *param,
+ int value));
+int evResetTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec, struct timespec));
+int evSetIdleTimer __P((evContext, evTimerFunc, void *, struct timespec,
+ evTimerID *));
+int evClearIdleTimer __P((evContext, evTimerID));
+int evResetIdleTimer __P((evContext, evTimerID, evTimerFunc, void *,
+ struct timespec));
+int evTouchIdleTimer __P((evContext, evTimerID));
+
+/* ev_waits.c */
+#define evWaitFor __evWaitFor
+#define evDo __evDo
+#define evUnwait __evUnwait
+#define evDefer __evDefer
+
+int evWaitFor __P((evContext, const void *, evWaitFunc, void *, evWaitID *));
+int evDo __P((evContext, const void *));
+int evUnwait __P((evContext, evWaitID));
+int evDefer __P((evContext, evWaitFunc, void *));
+
+#ifdef __EVENTLIB_P_DEFINED
+# undef __P
+#endif
+
+#endif /*_EVENTLIB_H*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/heap.h b/usr/src/lib/libresolv2_joy/include/isc/heap.h
new file mode 100644
index 0000000000..384d507cf5
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/heap.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+typedef int (*heap_higher_priority_func)(void *, void *);
+typedef void (*heap_index_func)(void *, int);
+typedef void (*heap_for_each_func)(void *, void *);
+
+typedef struct heap_context {
+ int array_size;
+ int array_size_increment;
+ int heap_size;
+ void **heap;
+ heap_higher_priority_func higher_priority;
+ heap_index_func index;
+} *heap_context;
+
+#define heap_new __heap_new
+#define heap_free __heap_free
+#define heap_insert __heap_insert
+#define heap_delete __heap_delete
+#define heap_increased __heap_increased
+#define heap_decreased __heap_decreased
+#define heap_element __heap_element
+#define heap_for_each __heap_for_each
+
+heap_context heap_new(heap_higher_priority_func, heap_index_func, int);
+int heap_free(heap_context);
+int heap_insert(heap_context, void *);
+int heap_delete(heap_context, int);
+int heap_increased(heap_context, int);
+int heap_decreased(heap_context, int);
+void * heap_element(heap_context, int);
+int heap_for_each(heap_context, heap_for_each_func, void *);
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/irpmarshall.h b/usr/src/lib/libresolv2_joy/include/isc/irpmarshall.h
new file mode 100644
index 0000000000..244b3e3460
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/irpmarshall.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: irpmarshall.h,v 1.4 2005/04/27 04:56:17 sra Exp $
+ */
+
+#ifndef _IRPMARSHALL_H_INCLUDED
+#define _IRPMARSHALL_H_INCLUDED
+
+/* Hide function names */
+#define irp_marshall_gr __irp_marshall_gr
+#define irp_marshall_ho __irp_marshall_ho
+#define irp_marshall_ne __irp_marshall_ne
+#define irp_marshall_ng __irp_marshall_ng
+#define irp_marshall_nw __irp_marshall_nw
+#define irp_marshall_pr __irp_marshall_pr
+#define irp_marshall_pw __irp_marshall_pw
+#define irp_marshall_sv __irp_marshall_sv
+#define irp_unmarshall_gr __irp_unmarshall_gr
+#define irp_unmarshall_ho __irp_unmarshall_ho
+#define irp_unmarshall_ne __irp_unmarshall_ne
+#define irp_unmarshall_ng __irp_unmarshall_ng
+#define irp_unmarshall_nw __irp_unmarshall_nw
+#define irp_unmarshall_pr __irp_unmarshall_pr
+#define irp_unmarshall_pw __irp_unmarshall_pw
+#define irp_unmarshall_sv __irp_unmarshall_sv
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+ (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+/* See comment below on usage */
+int irp_marshall_pw(const struct passwd *, char **, size_t *);
+int irp_unmarshall_pw(struct passwd *, char *);
+int irp_marshall_gr(const struct group *, char **, size_t *);
+int irp_unmarshall_gr(struct group *, char *);
+int irp_marshall_sv(const struct servent *, char **, size_t *);
+int irp_unmarshall_sv(struct servent *, char *);
+int irp_marshall_pr(struct protoent *, char **, size_t *);
+int irp_unmarshall_pr(struct protoent *, char *);
+int irp_marshall_ho(struct hostent *, char **, size_t *);
+int irp_unmarshall_ho(struct hostent *, char *);
+int irp_marshall_ng(const char *, const char *, const char *,
+ char **, size_t *);
+int irp_unmarshall_ng(const char **, const char **, const char **, char *);
+int irp_marshall_nw(struct nwent *, char **, size_t *);
+int irp_unmarshall_nw(struct nwent *, char *);
+int irp_marshall_ne(struct netent *, char **, size_t *);
+int irp_unmarshall_ne(struct netent *, char *);
+
+/*! \file
+ * \brief
+ * Functions to marshall and unmarshall various system data structures. We
+ * use a printable ascii format that is as close to various system config
+ * files as reasonable (e.g. /etc/passwd format).
+ *
+ * We are not forgiving with unmarhsalling misformatted buffers. In
+ * particular whitespace in fields is not ignored. So a formatted password
+ * entry "brister :1364:100:...." will yield a username of "brister "
+ *
+ * We potentially do a lot of mallocs to fill fields that are of type
+ * (char **) like a hostent h_addr field. Building (for example) the
+ * h_addr field and its associated addresses all in one buffer is
+ * certainly possible, but not done here.
+ *
+ * The following description is true for all the marshalling functions:
+ *
+ * int irp_marshall_XX(struct yyyy *XX, char **buffer, size_t *len);
+ *
+ * The argument XX (of type struct passwd for example) is marshalled in the
+ * buffer pointed at by *BUFFER, which is of length *LEN. Returns 0
+ * on success and -1 on failure. Failure will occur if *LEN is
+ * smaller than needed.
+ *
+ * If BUFFER is NULL, then *LEN is set to the size of the buffer
+ * needed to marshall the data and no marshalling is actually done.
+ *
+ * If *BUFFER is NULL, then a buffer large enough will be allocated
+ * with memget() and the size allocated will be stored in *LEN. An extra 2
+ * bytes will be allocated for the client to append CRLF if wanted. The
+ * value of *LEN will include these two bytes.
+ *
+ * All the marshalling functions produce a buffer with the fields
+ * separated by colons (except for the hostent marshalling, which uses '@'
+ * to separate fields). Fields that have multiple subfields (like the
+ * gr_mem field in struct group) have their subparts separated by
+ * commas.
+ *
+ * int irp_unmarshall_XX(struct YYYYY *XX, char *buffer);
+ *
+ * The unmashalling functions break apart the buffer and store the
+ * values in the struct pointed to by XX. All pointer values inside
+ * XX are allocated with malloc. All arrays of pointers have a NULL
+ * as the last element.
+ */
+
+#endif
diff --git a/usr/src/lib/libresolv2_joy/include/isc/list.h b/usr/src/lib/libresolv2_joy/include/isc/list.h
new file mode 100644
index 0000000000..5fe9031141
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/list.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LIST_H
+#define LIST_H 1
+#include <isc/assertions.h>
+
+#define LIST(type) struct { type *head, *tail; }
+#define INIT_LIST(list) \
+ do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LINK(type) struct { type *prev, *next; }
+#define INIT_LINK_TYPE(elt, link, type) \
+ do { \
+ (elt)->link.prev = (type *)(-1); \
+ (elt)->link.next = (type *)(-1); \
+ } while (0)
+#define INIT_LINK(elt, link) \
+ INIT_LINK_TYPE(elt, link, void)
+#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1) && \
+ (void *)((elt)->link.next) != (void *)(-1))
+
+#define HEAD(list) ((list).head)
+#define TAIL(list) ((list).tail)
+#define EMPTY(list) ((list).head == NULL)
+
+#define PREPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).head != NULL) \
+ (list).head->link.prev = (elt); \
+ else \
+ (list).tail = (elt); \
+ (elt)->link.prev = NULL; \
+ (elt)->link.next = (list).head; \
+ (list).head = (elt); \
+ } while (0)
+
+#define APPEND(list, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((list).tail != NULL) \
+ (list).tail->link.next = (elt); \
+ else \
+ (list).head = (elt); \
+ (elt)->link.prev = (list).tail; \
+ (elt)->link.next = NULL; \
+ (list).tail = (elt); \
+ } while (0)
+
+#define UNLINK_TYPE(list, elt, link, type) \
+ do { \
+ INSIST(LINKED(elt, link));\
+ if ((elt)->link.next != NULL) \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ else { \
+ INSIST((list).tail == (elt)); \
+ (list).tail = (elt)->link.prev; \
+ } \
+ if ((elt)->link.prev != NULL) \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ else { \
+ INSIST((list).head == (elt)); \
+ (list).head = (elt)->link.next; \
+ } \
+ INIT_LINK_TYPE(elt, link, type); \
+ } while (0)
+#define UNLINK(list, elt, link) \
+ UNLINK_TYPE(list, elt, link, void)
+
+#define PREV(elt, link) ((elt)->link.prev)
+#define NEXT(elt, link) ((elt)->link.next)
+
+#define INSERT_BEFORE(list, before, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((before)->link.prev == NULL) \
+ PREPEND(list, elt, link); \
+ else { \
+ (elt)->link.prev = (before)->link.prev; \
+ (before)->link.prev = (elt); \
+ (elt)->link.prev->link.next = (elt); \
+ (elt)->link.next = (before); \
+ } \
+ } while (0)
+
+#define INSERT_AFTER(list, after, elt, link) \
+ do { \
+ INSIST(!LINKED(elt, link));\
+ if ((after)->link.next == NULL) \
+ APPEND(list, elt, link); \
+ else { \
+ (elt)->link.next = (after)->link.next; \
+ (after)->link.next = (elt); \
+ (elt)->link.next->link.prev = (elt); \
+ (elt)->link.prev = (after); \
+ } \
+ } while (0)
+
+#define ENQUEUE(list, elt, link) APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) UNLINK(list, elt, link)
+
+#endif /* LIST_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/logging.h b/usr/src/lib/libresolv2_joy/include/isc/logging.h
new file mode 100644
index 0000000000..c539443ff8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/logging.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define log_critical (-5)
+#define log_error (-4)
+#define log_warning (-3)
+#define log_notice (-2)
+#define log_info (-1)
+#define log_debug(level) (level)
+
+typedef enum { log_syslog, log_file, log_null } log_channel_type;
+
+#define LOG_MAX_VERSIONS 99
+
+#define LOG_CLOSE_STREAM 0x0001
+#define LOG_TIMESTAMP 0x0002
+#define LOG_TRUNCATE 0x0004
+#define LOG_USE_CONTEXT_LEVEL 0x0008
+#define LOG_PRINT_LEVEL 0x0010
+#define LOG_REQUIRE_DEBUG 0x0020
+#define LOG_CHANNEL_BROKEN 0x0040
+#define LOG_PRINT_CATEGORY 0x0080
+#define LOG_CHANNEL_OFF 0x0100
+
+typedef struct log_context *log_context;
+typedef struct log_channel *log_channel;
+
+#define LOG_OPTION_DEBUG 0x01
+#define LOG_OPTION_LEVEL 0x02
+
+#define log_open_stream __log_open_stream
+#define log_close_stream __log_close_stream
+#define log_get_stream __log_get_stream
+#define log_get_filename __log_get_filename
+#define log_check_channel __log_check_channel
+#define log_check __log_check
+#define log_vwrite __log_vwrite
+#define log_write __log_write
+#define log_new_context __log_new_context
+#define log_free_context __log_free_context
+#define log_add_channel __log_add_channel
+#define log_remove_channel __log_remove_channel
+#define log_option __log_option
+#define log_category_is_active __log_category_is_active
+#define log_new_syslog_channel __log_new_syslog_channel
+#define log_new_file_channel __log_new_file_channel
+#define log_set_file_owner __log_set_file_owner
+#define log_new_null_channel __log_new_null_channel
+#define log_inc_references __log_inc_references
+#define log_dec_references __log_dec_references
+#define log_get_channel_type __log_get_channel_type
+#define log_free_channel __log_free_channel
+#define log_close_debug_channels __log_close_debug_channels
+
+FILE * log_open_stream(log_channel);
+int log_close_stream(log_channel);
+FILE * log_get_stream(log_channel);
+char * log_get_filename(log_channel);
+int log_check_channel(log_context, int, log_channel);
+int log_check(log_context, int, int);
+#ifdef __GNUC__
+void log_vwrite(log_context, int, int, const char *,
+ va_list args)
+ __attribute__((__format__(__printf__, 4, 0)));
+void log_write(log_context, int, int, const char *, ...)
+ __attribute__((__format__(__printf__, 4, 5)));
+#else
+void log_vwrite(log_context, int, int, const char *,
+ va_list args);
+void log_write(log_context, int, int, const char *, ...);
+#endif
+int log_new_context(int, char **, log_context *);
+void log_free_context(log_context);
+int log_add_channel(log_context, int, log_channel);
+int log_remove_channel(log_context, int, log_channel);
+int log_option(log_context, int, int);
+int log_category_is_active(log_context, int);
+log_channel log_new_syslog_channel(unsigned int, int, int);
+log_channel log_new_file_channel(unsigned int, int, const char *,
+ FILE *, unsigned int,
+ unsigned long);
+int log_set_file_owner(log_channel, uid_t, gid_t);
+log_channel log_new_null_channel(void);
+int log_inc_references(log_channel);
+int log_dec_references(log_channel);
+log_channel_type log_get_channel_type(log_channel);
+int log_free_channel(log_channel);
+void log_close_debug_channels(log_context);
+
+#endif /* !LOGGING_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/memcluster.h b/usr/src/lib/libresolv2_joy/include/isc/memcluster.h
new file mode 100644
index 0000000000..0923deb5e7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/memcluster.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1997,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MEMCLUSTER_H
+#define MEMCLUSTER_H
+
+#include <stdio.h>
+
+#define meminit __meminit
+#ifdef MEMCLUSTER_DEBUG
+#define memget(s) __memget_debug(s, __FILE__, __LINE__)
+#define memput(p, s) __memput_debug(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_DEBUG*/
+#ifdef MEMCLUSTER_RECORD
+#define memget(s) __memget_record(s, __FILE__, __LINE__)
+#define memput(p, s) __memput_record(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_RECORD*/
+#define memget __memget
+#define memput __memput
+#endif /*MEMCLUSTER_RECORD*/
+#endif /*MEMCLUSTER_DEBUG*/
+#define memstats __memstats
+#define memactive __memactive
+
+int meminit(size_t, size_t);
+void * __memget(size_t);
+void __memput(void *, size_t);
+void * __memget_debug(size_t, const char *, int);
+void __memput_debug(void *, size_t, const char *, int);
+void * __memget_record(size_t, const char *, int);
+void __memput_record(void *, size_t, const char *, int);
+void memstats(FILE *);
+int memactive(void);
+
+#endif /* MEMCLUSTER_H */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/misc.h b/usr/src/lib/libresolv2_joy/include/isc/misc.h
new file mode 100644
index 0000000000..b54f4ee6ed
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/misc.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1995-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: misc.h,v 1.7 2008/11/14 02:36:51 marka Exp $
+ */
+
+#ifndef _ISC_MISC_H
+#define _ISC_MISC_H
+
+/*! \file */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#define bitncmp __bitncmp
+/*#define isc_movefile __isc_movefile */
+
+extern int bitncmp(const void *, const void *, int);
+extern int isc_movefile(const char *, const char *);
+
+extern int isc_gethexstring(unsigned char *, size_t, int, FILE *,
+ int *);
+extern void isc_puthexstring(FILE *, const unsigned char *, size_t,
+ size_t, size_t, const char *);
+extern void isc_tohex(const unsigned char *, size_t, char *);
+
+#endif /*_ISC_MISC_H*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/isc/platform.h b/usr/src/lib/libresolv2_joy/include/isc/platform.h
new file mode 100644
index 0000000000..2fc59b61a8
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/platform.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: platform.h.in,v 1.3 2008/01/23 02:15:56 tbox Exp $ */
+
+/*! \file */
+
+#ifndef ISC_PLATFORM_H
+#define ISC_PLATFORM_H
+
+/*
+ * Define if the OS does not define struct timespec.
+ */
+#undef ISC_PLATFORM_NEEDTIMESPEC
+#ifdef ISC_PLATFORM_NEEDTIMESPEC
+#include <time.h> /* For time_t */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+
+#endif
diff --git a/usr/src/lib/libresolv2_joy/include/isc/tree.h b/usr/src/lib/libresolv2_joy/include/isc/tree.h
new file mode 100644
index 0000000000..96feaca68d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/isc/tree.h
@@ -0,0 +1,59 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 1.3 2005/04/27 04:56:18 sra Exp $
+ */
+
+
+#ifndef _TREE_H_INCLUDED
+#define _TREE_H_INCLUDED
+
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/*%
+ * tree_t is our package-specific anonymous pointer.
+ */
+#if defined(__STDC__) || defined(__GNUC__)
+typedef void *tree_t;
+#else
+typedef char *tree_t;
+#endif
+
+/*%
+ * Do not taint namespace
+ */
+#define tree_add __tree_add
+#define tree_delete __tree_delete
+#define tree_init __tree_init
+#define tree_mung __tree_mung
+#define tree_srch __tree_srch
+#define tree_trav __tree_trav
+
+
+typedef struct tree_s {
+ tree_t data;
+ struct tree_s *left, *right;
+ short bal;
+ }
+ tree;
+
+
+void tree_init __P((tree **));
+tree_t tree_srch __P((tree **, int (*)(), tree_t));
+tree_t tree_add __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_delete __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_trav __P((tree **, int (*)()));
+void tree_mung __P((tree **, void (*)()));
+
+
+#endif /* _TREE_H_INCLUDED */
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/make_os_version b/usr/src/lib/libresolv2_joy/include/make_os_version
new file mode 100755
index 0000000000..3654490fee
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/make_os_version
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+UNAME_R=`/usr/bin/uname -r`
+
+OS_MAJOR=`echo $UNAME_R | /usr/bin/sed -e 's/^\([^.]*\).*/\1/'`
+OS_MINOR=`echo $UNAME_R | /usr/bin/sed -e 's/^[^.]*\.\([^.]*\).*/\1/'`
+OS_VERSION=`echo $UNAME_R | tr '.' '_'`
+
+cat <<EOF > new_os_version.h
+#ifndef OS_VERSION_H
+#define OS_VERSION_H
+
+#define SUNOS_$OS_VERSION
+#define OS_MAJOR $OS_MAJOR
+#define OS_MINOR $OS_MINOR
+
+#endif
+EOF
+
+if [ -f os_version.h ]; then
+ if /usr/bin/cmp -s new_os_version.h os_version.h; then
+ /usr/bin/rm -f new_os_version.h
+ else
+ /usr/bin/rm -f os_version.h
+ /usr/bin/mv new_os_version.h os_version.h
+ fi
+else
+ /usr/bin/mv new_os_version.h os_version.h
+fi
diff --git a/usr/src/lib/libresolv2_joy/include/make_os_version.sh b/usr/src/lib/libresolv2_joy/include/make_os_version.sh
new file mode 100644
index 0000000000..3654490fee
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/make_os_version.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+UNAME_R=`/usr/bin/uname -r`
+
+OS_MAJOR=`echo $UNAME_R | /usr/bin/sed -e 's/^\([^.]*\).*/\1/'`
+OS_MINOR=`echo $UNAME_R | /usr/bin/sed -e 's/^[^.]*\.\([^.]*\).*/\1/'`
+OS_VERSION=`echo $UNAME_R | tr '.' '_'`
+
+cat <<EOF > new_os_version.h
+#ifndef OS_VERSION_H
+#define OS_VERSION_H
+
+#define SUNOS_$OS_VERSION
+#define OS_MAJOR $OS_MAJOR
+#define OS_MINOR $OS_MINOR
+
+#endif
+EOF
+
+if [ -f os_version.h ]; then
+ if /usr/bin/cmp -s new_os_version.h os_version.h; then
+ /usr/bin/rm -f new_os_version.h
+ else
+ /usr/bin/rm -f os_version.h
+ /usr/bin/mv new_os_version.h os_version.h
+ fi
+else
+ /usr/bin/mv new_os_version.h os_version.h
+fi
diff --git a/usr/src/lib/libresolv2_joy/include/port_after.h b/usr/src/lib/libresolv2_joy/include/port_after.h
new file mode 100644
index 0000000000..c3abf4b334
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/port_after.h
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: port_after.h.in,v 1.60 2008/02/28 05:34:17 marka Exp $ */
+
+#ifndef port_after_h
+#define port_after_h
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#if (!defined(BSD)) || (BSD < 199306)
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+
+#ifdef REENABLE_SEND
+#undef send
+#endif
+
+#undef NEED_PSELECT
+#undef HAVE_SA_LEN
+#undef HAVE_MINIMUM_IFREQ
+#define NEED_DAEMON 1
+#undef NEED_STRSEP
+#undef NEED_STRERROR
+#ifdef NEED_STRERROR
+const char *isc_strerror(int);
+#define strerror isc_strerror
+#endif
+/* HAS_INET6_STRUCTS and HAVE_SIN6_SCOPE_ID are defined by port_ipv6.h
+ * #define HAS_INET6_STRUCTS 1
+ * #define HAVE_SIN6_SCOPE_ID 1
+ */
+#include <port_ipv6.h>
+
+#undef NEED_IN6ADDR_ANY
+#undef HAS_IN_ADDR6
+#define HAVE_SOCKADDR_STORAGE 1
+#undef NEED_GETTIMEOFDAY
+#define HAVE_STRNDUP
+#undef USE_FIONBIO_IOCTL
+#undef INNETGR_ARGS
+
+#undef USE_IFNAMELINKID
+#define PORT_NONBLOCK O_NONBLOCK
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+/*
+ * We need to know the IPv6 address family number even on IPv4-only systems.
+ * Note that this is NOT a protocol constant, and that if the system has its
+ * own AF_INET6, different from ours below, all of BIND's libraries and
+ * executables will need to be recompiled after the system <sys/socket.h>
+ * has had this type added. The type number below is correct on most BSD-
+ * derived systems for which AF_INET6 is defined.
+ */
+#ifndef AF_INET6
+#define AF_INET6 24
+#endif
+
+#ifndef PF_INET6
+#define PF_INET6 AF_INET6
+#endif
+
+#ifdef HAS_IN_ADDR6
+/* Map to pre-RFC structure. */
+#define in6_addr in_addr6
+#endif
+
+#ifndef HAS_INET6_STRUCTS
+/* Replace with structure from later rev of O/S if known. */
+struct in6_addr {
+ u_int8_t s6_addr[16];
+};
+
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+
+/* Replace with structure from later rev of O/S if known. */
+struct sockaddr_in6 {
+#ifdef HAVE_SA_LEN
+ u_int8_t sin6_len; /* length of this struct */
+ u_int8_t sin6_family; /* AF_INET6 */
+#else
+ u_int16_t sin6_family; /* AF_INET6 */
+#endif
+ u_int16_t sin6_port; /* transport layer port # */
+ u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ u_int32_t sin6_scope_id; /* set of interfaces for a scope */
+};
+#endif /* HAS_INET6_STRUCTS */
+
+#ifdef BROKEN_IN6ADDR_INIT_MACROS
+#undef IN6ADDR_ANY_INIT
+#undef IN6ADDR_LOOPBACK_INIT
+#endif
+
+#ifdef _AIX
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{{ 0, 0, 0, 0 }}}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#if BYTE_ORDER == BIG_ENDIAN
+#define IN6ADDR_LOOPBACK_INIT {{{ 0, 0, 0, 1 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT {{{0, 0, 0, 0x01000000}}}
+#endif
+#endif
+#endif
+
+#ifndef IN6ADDR_ANY_INIT
+#ifdef s6_addr
+#define IN6ADDR_ANY_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
+#else
+#define IN6ADDR_ANY_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
+#endif
+
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#ifdef s6_addr
+#define IN6ADDR_LOOPBACK_INIT \
+ {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
+#else
+#define IN6ADDR_LOOPBACK_INIT \
+ {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}
+#endif
+#endif
+
+#ifndef HAVE_SOCKADDR_STORAGE
+#define __SS_MAXSIZE 128
+#define __SS_ALLIGSIZE (sizeof (long))
+
+struct sockaddr_storage {
+#ifdef HAVE_SA_LEN
+ u_int8_t ss_len; /* address length */
+ u_int8_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - 2 * sizeof(u_int8_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#else
+ u_int16_t ss_family; /* address family */
+ char __ss_pad1[__SS_ALLIGSIZE - sizeof(u_int16_t)];
+ long __ss_align;
+ char __ss_pad2[__SS_MAXSIZE - 2 * __SS_ALLIGSIZE];
+#endif
+};
+#endif
+
+
+#if !defined(HAS_INET6_STRUCTS) || defined(NEED_IN6ADDR_ANY)
+#define in6addr_any isc_in6addr_any
+extern const struct in6_addr in6addr_any;
+#endif
+
+/*
+ * IN6_ARE_ADDR_EQUAL, IN6_IS_ADDR_UNSPECIFIED, IN6_IS_ADDR_V4COMPAT and
+ * IN6_IS_ADDR_V4MAPPED are broken in glibc 2.1.
+ */
+#ifdef __GLIBC__
+#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2)
+#undef IN6_ARE_ADDR_EQUAL
+#undef IN6_IS_ADDR_UNSPECIFIED
+#undef IN6_IS_ADDR_V4COMPAT
+#undef IN6_IS_ADDR_V4MAPPED
+#endif
+#endif
+
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL(a,b) \
+ (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0)
+#endif
+
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+ IN6_ARE_ADDR_EQUAL(a, &in6addr_any)
+#endif
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+extern const struct in6_addr isc_in6addr_loopback;
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ IN6_ARE_ADDR_EQUAL(a, &isc_in6addr_loopback)
+#endif
+
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((a)->s6_addr[0] == 0x00 && (a)->s6_addr[1] == 0x00 && \
+ (a)->s6_addr[2] == 0x00 && (a)->s6_addr[3] == 0x00 && \
+ (a)->s6_addr[4] == 0x00 && (a)->s6_addr[5] == 0x00 && \
+ (a)->s6_addr[6] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[8] == 0x00 && (a)->s6_addr[9] == 0x00 && \
+ (a)->s6_addr[10] == 0xff && (a)->s6_addr[11] == 0xff)
+#endif
+
+#ifndef IN6_IS_ADDR_SITELOCAL
+#define IN6_IS_ADDR_SITELOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
+#endif
+
+#ifndef IN6_IS_ADDR_LINKLOCAL
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
+#endif
+
+#ifndef IN6_IS_ADDR_MULTICAST
+#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff)
+#endif
+
+#ifndef __IPV6_ADDR_MC_SCOPE
+#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
+#endif
+
+#ifndef __IPV6_ADDR_SCOPE_SITELOCAL
+#define __IPV6_ADDR_SCOPE_SITELOCAL 0x05
+#endif
+#ifndef __IPV6_ADDR_SCOPE_ORGLOCAL
+#define __IPV6_ADDR_SCOPE_ORGLOCAL 0x08
+#endif
+
+#ifndef IN6_IS_ADDR_MC_SITELOCAL
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL))
+#endif
+
+#ifndef IN6_IS_ADDR_MC_ORGLOCAL
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+ (IN6_IS_ADDR_MULTICAST(a) && \
+ (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL))
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#ifndef INET6_ADDRSTRLEN
+/* sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:123.123.123.123") */
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef MIN
+#define MIN(x,y) (((x) <= (y)) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
+#endif
+
+#ifdef NEED_DAEMON
+int daemon(int nochdir, int noclose);
+#endif
+
+#ifdef NEED_STRSEP
+char * strsep(char **stringp, const char *delim);
+#endif
+
+#ifndef ALIGN
+#define ALIGN(p) (((uintptr_t)(p) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
+#endif
+
+#ifdef NEED_SETGROUPENT
+int setgroupent(int stayopen);
+#endif
+
+#ifdef NEED_GETGROUPLIST
+int getgrouplist(GETGROUPLIST_ARGS);
+#endif
+
+#ifdef POSIX_GETGRNAM_R
+int
+__posix_getgrnam_r(const char *, struct group *, char *, int, struct group **);
+#endif
+
+#ifdef NEED_GETGRNAM_R
+int
+getgrnam_r(const char *, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef POSIX_GETGRGID_R
+int
+__posix_getgrgid_r(gid_t, struct group *, char *, int, struct group **) ;
+#endif
+
+#ifdef NEED_GETGRGID_R
+int
+getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
+#endif
+
+#ifdef NEED_GETGRENT_R
+GROUP_R_RETURN getgrent_r(struct group *gptr, GROUP_R_ARGS);
+#endif
+
+#ifdef NEED_SETGRENT_R
+GROUP_R_SET_RETURN setgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#ifdef NEED_ENDGRENT_R
+GROUP_R_END_RETURN endgrent_r(GROUP_R_ENT_ARGS);
+#endif
+
+#if defined(NEED_INNETGR_R) && defined(NGR_R_RETURN)
+NGR_R_RETURN
+innetgr_r(const char *, const char *, const char *, const char *);
+#endif
+
+#ifdef NEED_SETNETGRENT_R
+#ifdef NGR_R_SET_ARGS
+NGR_R_SET_RETURN setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS);
+#else
+NGR_R_SET_RETURN setnetgrent_r(NGR_R_SET_CONST char *netgroup);
+#endif
+#endif
+
+#ifdef NEED_ENDNETGRENT_R
+#ifdef NGR_R_END_ARGS
+NGR_R_END_RETURN endnetgrent_r(NGR_R_END_ARGS);
+#else
+NGR_R_END_RETURN endnetgrent_r(void);
+#endif
+#endif
+
+#ifdef POSIX_GETPWNAM_R
+int
+__posix_getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_GETPWNAM_R
+int
+getpwnam_r(const char *login, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef POSIX_GETPWUID_R
+int
+__posix_getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, int buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_GETPWUID_R
+int
+getpwuid_r(uid_t uid, struct passwd *pwptr,
+ char *buf, size_t buflen, struct passwd **result);
+#endif
+
+#ifdef NEED_SETPWENT_R
+#ifdef PASS_R_ENT_ARGS
+PASS_R_SET_RETURN setpwent_r(PASS_R_ENT_ARGS);
+#else
+PASS_R_SET_RETURN setpwent_r(void);
+#endif
+
+#endif
+
+#ifdef NEED_SETPASSENT_R
+#ifdef PASS_R_ENT_ARGS
+PASS_R_SET_RETURN setpassent_r(int stayopen, PASS_R_ENT_ARGS);
+#else
+PASS_R_SET_RETURN setpassent_r(int stayopen);
+#endif
+#endif
+
+#ifdef NEED_GETPWENT_R
+PASS_R_RETURN getpwent_r(struct passwd *pwptr, PASS_R_ARGS);
+#endif
+
+#ifdef NEED_ENDPWENT_R
+void endpwent_r(void);
+#endif
+
+#ifdef NEED_SETPASSENT
+int setpassent(int stayopen);
+#endif
+
+#define gettimeofday isc__gettimeofday
+#ifdef NEED_GETTIMEOFDAY
+int isc__gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp);
+#else
+int isc__gettimeofday(struct timeval *tp, struct timezone *tzp);
+#endif
+
+int getnetgrent(NGR_R_CONST char **machinep, NGR_R_CONST char **userp,
+ NGR_R_CONST char **domainp);
+
+#ifdef NGR_R_ARGS
+int getnetgrent_r(NGR_R_CONST char **machinep, NGR_R_CONST char **userp,
+ NGR_R_CONST char **domainp, NGR_R_ARGS);
+#endif
+
+/* setnetgrent and endnetgrent are defined in sunw_port_after.h
+#ifdef SETNETGRENT_ARGS
+void setnetgrent(SETNETGRENT_ARGS);
+#else
+void setnetgrent(const char *netgroup);
+#endif
+
+void endnetgrent(void);
+*/
+
+#ifdef INNETGR_ARGS
+int innetgr(INNETGR_ARGS);
+#else
+int innetgr(const char *netgroup, const char *machine,
+ const char *user, const char *domain);
+#endif
+
+#ifdef NGR_R_SET_ARGS
+NGR_R_SET_RETURN
+setnetgrent_r(NGR_R_SET_CONST char *netgroup, NGR_R_SET_ARGS);
+#else
+NGR_R_SET_RETURN
+setnetgrent_r(NGR_R_SET_CONST char *netgroup);
+#endif
+
+#ifdef NEED_STRTOUL
+unsigned long strtoul(const char *, char **, int);
+#endif
+
+#ifdef NEED_SUN4PROTOS
+#include <stdarg.h>
+#ifndef __SIZE_TYPE__
+#define __SIZE_TYPE__ int
+#endif
+struct sockaddr;
+struct iovec;
+struct timeval;
+struct timezone;
+int fprintf(FILE *, const char *, ...);
+int getsockname(int, struct sockaddr *, int *);
+int getpeername(int, struct sockaddr *, int *);
+int socket(int, int, int);
+int connect(int, const struct sockaddr *, int);
+int writev(int, struct iovec *, int);
+int readv(int, struct iovec *, int);
+int send(int, const char *, int, int);
+void bzero(char *, int);
+int recvfrom(int, char *, int, int, struct sockaddr *, int *);
+int syslog(int, const char *, ... );
+int printf(const char *, ...);
+__SIZE_TYPE__ fread(void *, __SIZE_TYPE__, __SIZE_TYPE__, FILE *);
+__SIZE_TYPE__ fwrite(const void *, __SIZE_TYPE__, __SIZE_TYPE__, FILE *);
+int fclose(FILE *);
+int ungetc(int, FILE *);
+int scanf(const char *, ...);
+int sscanf(const char *, const char *, ... );
+int tolower(int);
+int toupper(int);
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, int);
+int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#ifdef gettimeofday
+#undef gettimeofday
+int gettimeofday(struct timeval *, struct timezone *);
+#define gettimeofday isc__gettimeofday
+#else
+int gettimeofday(struct timeval *, struct timezone *);
+#endif
+long strtol(const char*, char **, int);
+int fseek(FILE *, long, int);
+int setsockopt(int, int, int, const char *, int);
+int bind(int, const struct sockaddr *, int);
+void bcopy(char *, char *, int);
+int fputc(char, FILE *);
+int listen(int, int);
+int accept(int, struct sockaddr *, int *);
+int getsockopt(int, int, int, char *, int *);
+int vfprintf(FILE *, const char *, va_list);
+int fflush(FILE *);
+int fgetc(FILE *);
+int fputs(const char *, FILE *);
+int fchown(int, int, int);
+void setbuf(FILE *, char *);
+int gethostname(char *, int);
+int rename(const char *, const char *);
+time_t time(time_t *);
+int fscanf(FILE *, const char *, ...);
+int sscanf(const char *, const char *, ...);
+int ioctl(int, int, caddr_t);
+void perror(const char *);
+
+#if !defined(__USE_FIXED_PROTOTYPES__) && !defined(__cplusplus) && !defined(__STRICT_ANSI__)
+/*
+ * 'gcc -ansi' changes the prototype for vsprintf().
+ * Use this prototype when 'gcc -ansi' is not in effect.
+ */
+char *vsprintf(char *, const char *, va_list);
+#endif
+#endif
+
+/* Solaris-specific changes */
+#include "sunw_port_after.h"
+
+#endif /* port_after_h */
diff --git a/usr/src/lib/libresolv2_joy/include/port_before.h b/usr/src/lib/libresolv2_joy/include/port_before.h
new file mode 100644
index 0000000000..2801139223
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/port_before.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (C) 2005-2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: port_before.h.in,v 1.31 2008/02/28 05:36:10 marka Exp $ */
+
+#ifndef port_before_h
+#define port_before_h
+/* Solaris-specific changes */
+#include "sunw_port_before.h"
+#include <config.h>
+
+#ifdef NEED_SUN4PROTOS
+#define _PARAMS(x) x
+#endif
+
+struct group; /* silence warning */
+struct passwd; /* silence warning */
+struct timeval; /* silence warning */
+struct timezone; /* silence warning */
+
+#ifdef HAVE_SYS_TIMERS_H
+#include <sys/timers.h>
+#endif
+#include <limits.h>
+
+#ifdef ISC_PLATFORM_NEEDTIMESPEC
+#include <time.h> /* For time_t */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+#ifndef HAVE_MEMMOVE
+#define memmove(a,b,c) bcopy(b,a,c)
+#endif
+
+#undef WANT_IRS_GR
+#undef WANT_IRS_NIS
+#undef WANT_IRS_PW
+
+#define BSD_COMP 1
+#define USE_POLL 1
+#define HAVE_MD5 1
+#define SOLARIS2 1
+
+/* DO_PTHREADS is conditionally defined in sunw_port_before.h
+ * #define DO_PTHREADS 1 */
+#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups
+#define GETNETBYADDR_ADDR_T long
+#define SETPWENT_VOID 1
+#define SETGRENT_VOID 1
+
+#define NET_R_ARGS char *buf, int buflen
+#define NET_R_BAD NULL
+#define NET_R_COPY buf, buflen
+#define NET_R_COPY_ARGS NET_R_ARGS
+#define NET_R_END_RESULT(x) /*empty*/
+#define NET_R_END_RETURN void
+#undef NET_R_ENT_ARGS /*empty*/
+#define NET_R_OK nptr
+#define NET_R_RETURN struct netent *
+#undef NET_R_SET_RESULT /*empty*/
+#undef NET_R_SETANSWER
+#define NET_R_SET_RETURN void
+#undef NETENT_DATA
+
+#define GROUP_R_RETURN struct group *
+#define GROUP_R_SET_RETURN void
+#undef GROUP_R_SET_RESULT /*empty*/
+#define GROUP_R_END_RETURN void
+#define GROUP_R_END_RESULT(x) /*empty*/
+#define GROUP_R_ARGS char *buf, int buflen
+#define GROUP_R_ENT_ARGS void
+#define GROUP_R_OK gptr
+#define GROUP_R_BAD NULL
+
+#define HOST_R_ARGS char *buf, int buflen, int *h_errnop
+#define HOST_R_BAD NULL
+#define HOST_R_COPY buf, buflen
+#define HOST_R_COPY_ARGS char *buf, int buflen
+#define HOST_R_END_RESULT(x) /*empty*/
+#define HOST_R_END_RETURN void
+#undef HOST_R_ENT_ARGS /*empty*/
+#define HOST_R_ERRNO *h_errnop = h_errno
+#define HOST_R_OK hptr
+#define HOST_R_RETURN struct hostent *
+#undef HOST_R_SETANSWER
+#undef HOST_R_SET_RESULT
+#define HOST_R_SET_RETURN void
+#undef HOSTENT_DATA
+
+#define NGR_R_ARGS char *buf, int buflen
+#define NGR_R_BAD (0)
+#define NGR_R_COPY buf, buflen
+#define NGR_R_COPY_ARGS NGR_R_ARGS
+#define NGR_R_CONST
+#define NGR_R_END_RESULT(x) /*empty*/
+#define NGR_R_END_RETURN void
+#undef NGR_R_END_ARGS /*empty*/
+#define NGR_R_OK 1
+#define NGR_R_RETURN int
+#define NGR_R_SET_CONST const
+#undef NGR_R_SET_RESULT /*empty*/
+#define NGR_R_SET_RETURN void
+#undef NGR_R_SET_ARGS
+
+
+#if !defined(NGR_R_SET_ARGS) && defined(NGR_R_END_ARGS)
+#define NGR_R_SET_ARGS NGR_R_END_ARGS
+#endif
+
+#define PROTO_R_ARGS char *buf, int buflen
+#define PROTO_R_BAD NULL
+#define PROTO_R_COPY buf, buflen
+#define PROTO_R_COPY_ARGS PROTO_R_ARGS
+#define PROTO_R_END_RESULT(x) /*empty*/
+#define PROTO_R_END_RETURN void
+#undef PROTO_R_ENT_ARGS /*empty*/
+#undef PROTO_R_ENT_UNUSED
+#define PROTO_R_OK pptr
+#undef PROTO_R_SETANSWER
+#define PROTO_R_RETURN struct protoent *
+#undef PROTO_R_SET_RESULT
+#define PROTO_R_SET_RETURN void
+#undef PROTOENT_DATA
+
+#define PASS_R_ARGS char *buf, int buflen
+#define PASS_R_BAD NULL
+#define PASS_R_COPY buf, buflen
+#define PASS_R_COPY_ARGS PASS_R_ARGS
+#define PASS_R_END_RESULT(x) /*empty*/
+#define PASS_R_END_RETURN void
+#undef PASS_R_ENT_ARGS
+#define PASS_R_OK pwptr
+#define PASS_R_RETURN struct passwd *
+#undef PASS_R_SET_RESULT /*empty*/
+#define PASS_R_SET_RETURN void
+
+#define SERV_R_ARGS char *buf, int buflen
+#define SERV_R_BAD NULL
+#define SERV_R_COPY buf, buflen
+#define SERV_R_COPY_ARGS SERV_R_ARGS
+#define SERV_R_END_RESULT(x) /*empty*/
+#define SERV_R_END_RETURN void
+#undef SERV_R_ENT_ARGS /*empty*/
+#undef SERV_R_ENT_UNUSED /*empty*/
+#define SERV_R_OK sptr
+#undef SERV_R_SETANSWER
+#define SERV_R_RETURN struct servent *
+#undef SERV_R_SET_RESULT
+#define SERV_R_SET_RETURN void
+
+
+
+#define DE_CONST(konst, var) \
+ do { \
+ union { const void *k; void *v; } _u; \
+ _u.k = konst; \
+ var = _u.v; \
+ } while (0)
+
+#define UNUSED(x) (x) = (x)
+
+#undef NEED_SOLARIS_BITTYPES
+#define ISC_SOCKLEN_T int
+
+#ifdef __GNUC__
+#define ISC_FORMAT_PRINTF(fmt, args) \
+ __attribute__((__format__(__printf__, fmt, args)))
+#else
+#define ISC_FORMAT_PRINTF(fmt, args)
+#endif
+
+/* Pull in host order macros when _XOPEN_SOURCE_EXTENDED is defined. */
+#if defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
+#include <sys/byteorder.h>
+#endif
+
+#endif
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/port_netdb.h b/usr/src/lib/libresolv2_joy/include/port_netdb.h
new file mode 100644
index 0000000000..a308cc7efa
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/port_netdb.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _PORT_NETDB_H
+#define _PORT_NETDB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* AI_NUMERICSERV is not a valid flag for getaddrinfo */
+#define AI_MASK 0x0038 /* mask of valid flags */
+
+/* EAI_OVERFLOW was removed from ISC */
+#define EAI_BADHINTS 12
+
+/*
+ * these are libresolv2 functions that were renamed in previous versions to
+ * res_* because they conflict with libnsl or libsocket
+ */
+
+#define endhostent joy_res_endhostent /* libnsl */
+void endhostent __P((void));
+#define endnetent res_endnetent /* libsocket */
+void endnetent __P((void));
+#define freeaddrinfo res_freeaddrinfo /* libsocket */
+void freeaddrinfo __P((struct addrinfo *));
+#define freehostent res_freehostent /* libsocket and libnsl */
+void freehostent __P((struct hostent *));
+#define getaddrinfo res_getaddrinfo /* libsocket */
+int getaddrinfo __P((const char *, const char *,
+ const struct addrinfo *, struct addrinfo **));
+#define gethostbyaddr joy_res_gethostbyaddr /* libnsl */
+struct hostent *gethostbyaddr __P((const char *, int, int));
+#define gethostbyname joy_res_gethostbyname /* libnsl */
+struct hostent *gethostbyname __P((const char *));
+#define gethostbyname2 joy_res_gethostbyname2 /* lib/nsswitch/dns */
+struct hostent *gethostbyname2 __P((const char *, int));
+#define gethostent res_gethostent /* libnsl */
+struct hostent *gethostent __P((void));
+#define getipnodebyaddr res_getipnodebyaddr /* libnsl and libsocket */
+struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *));
+#define getipnodebyname res_getipnodebyname /* libnsl and libsocket */
+struct hostent *getipnodebyname __P((const char *, int, int, int *));
+
+#define getnetbyaddr res_getnetbyaddr /* libsocket */
+struct netent *getnetbyaddr __P((unsigned long, int));
+#define getnetbyname res_getnetbyname /* libsocket */
+struct netent *getnetbyname __P((const char *));
+#define getnetent res_getnetent /* libsocket */
+struct netent *getnetent __P((void));
+#define sethostent joy_res_sethostent /* libnsl */
+void sethostent __P((int));
+#define setnetent res_setnetent /* libsocket */
+void setnetent __P((int));
+
+/*
+ * these are other irs functions now included in libresolv.so.2. We rename the
+ * ones that overlap with libsocket or libnsl
+ */
+
+/* endprotoent is in libsocket.so.1 */
+#define endprotoent res_endprotoent
+void endprotoent __P((void));
+
+/* endservent is in libsocket.so.1 */
+#define endservent res_endservent
+void endservent __P((void));
+
+/* note: the next two symbols are variables, not functions */
+
+/* gai_errlist is in libsocket.so.1 */
+#define gai_errlist res_gai_errlist
+
+/* gai_nerr is in libsocket.so.1 */
+#define gai_nerr res_gai_nerr
+
+/* gai_strerror is in libsocket.so.1 */
+#define gai_strerror res_gai_strerror
+const char *gai_strerror __P((int ecode));
+
+/* gethostbyaddr_r is in libnsl.so.1 */
+#define gethostbyaddr_r res_gethostbyaddr_r
+struct hostent *gethostbyaddr_r __P((const char *addr, int len, int type,
+ struct hostent *hptr, char *buf,
+ int buflen, int *h_errnop));
+
+/* gethostbyname_r is in libnsl.so.1 */
+#define gethostbyname_r res_gethostbyname_r
+struct hostent *gethostbyname_r __P((const char *name, struct hostent *hptr,
+ char *buf, int buflen, int *h_errnop));
+
+/* gethostent_r is in libnsl.so.1 */
+#define gethostent_r res_gethostent_r
+struct hostent *gethostent_r __P((struct hostent *hptr, char *buf, int buflen,
+ int *h_errnop));
+
+/* getnameinfo is in libsocket.so.1 */
+#define getnameinfo res_getnameinfo
+int getnameinfo __P((const struct sockaddr *, size_t, char *,
+ size_t, char *, size_t, int));
+
+/* getnetbyaddr_r is in libsocket.so.1 */
+#define getnetbyaddr_r res_getnetbyaddr_r
+struct netent *getnetbyaddr_r __P((long, int, struct netent *, char *, int));
+
+/* getnetbyname_r is in libsocket.so.1 */
+#define getnetbyname_r res_getnetbyname_r
+struct netent *getnetbyname_r __P((const char *, struct netent *, char *, int));
+
+/* getnetent_r is in libsocket.so.1 */
+#define getnetent_r res_getnetent_r
+struct netent *getnetent_r __P((struct netent *, char *, int));
+
+/* getprotobyname is in libsocket.so.1 */
+#define getprotobyname res_getprotobyname
+struct protoent *getprotobyname __P((const char *));
+
+/* getprotobyname_r is in libsocket.so.1 */
+#define getprotobyname_r res_getprotobyname_r
+struct protoent *getprotobyname_r __P((const char *, struct protoent *,
+ char *, int));
+
+/* getprotobynumber is in libsocket.so.1 */
+#define getprotobynumber res_getprotobynumber
+struct protoent *getprotobynumber __P((int));
+
+/* getprotobynumber_r is in libsocket.so.1 */
+#define getprotobynumber_r res_getprotobynumber_r
+struct protoent *getprotobynumber_r __P((int,
+ struct protoent *, char *, int));
+
+/* getprotoent is in libsocket.so.1 */
+#define getprotoent res_getprotoent
+struct protoent *getprotoent __P((void));
+
+/* getprotoent_r is in libsocket.so.1 */
+#define getprotoent_r res_getprotoent_r
+struct protoent *getprotoent_r __P((struct protoent *, char *, int));
+
+/* getservbyname is in libsocket.so.1 and libnsl.so.1 */
+#define getservbyname res_getservbyname
+struct servent *getservbyname __P((const char *, const char *));
+
+/* getservbyname_r is in libsocket.so.1 and libnsl.so.1 */
+#define getservbyname_r res_getservbyname_r
+struct servent *getservbyname_r __P((const char *name, const char *,
+ struct servent *, char *, int));
+
+/* getservbyport is in libsocket.so.1 and libnsl.so.1 */
+#define getservbyport res_getservbyport
+struct servent *getservbyport __P((int, const char *));
+
+/* getservbyport_r is in libsocket.so.1 and libnsl.so.1 */
+#define getservbyport_r res_getservbyport_r
+struct servent *getservbyport_r __P((int port, const char *,
+ struct servent *, char *, int));
+
+/* getservent is in libsocket.so.1 */
+#define getservent res_getservent
+struct servent *getservent __P((void));
+
+/* getservent_r is in libsocket.so.1 */
+#define getservent_r res_getservent_r
+struct servent *getservent_r __P((struct servent *, char *, int));
+
+/* innetgr is in libsocket.so.1 */
+#define innetgr res_innetgr
+int innetgr __P((const char *, const char *, const char *, const char *));
+
+/* setprotoent is in libsocket.so.1 */
+#define setprotoent res_setprotoent
+void setprotoent __P((int));
+
+/* setservent is in libsocket.so.1 */
+#define setservent res_setservent
+void setservent __P((int));
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PORT_NETDB_H */
diff --git a/usr/src/lib/libresolv2_joy/include/port_resolv.h b/usr/src/lib/libresolv2_joy/include/port_resolv.h
new file mode 100644
index 0000000000..cd1a97d40c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/port_resolv.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PORT_RESOLV_H
+#define _PORT_RESOLV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* RES_NSID has the same value as RES_NO_NIBBLE, which has been deleted */
+#define RES_NSID 0x00040000 /* request name server ID */
+
+/* RES_DEFAULT has a new value in libbind-6.0 */
+#undef RES_DEFAULT
+#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | \
+ RES_DNSRCH | RES_NO_NIBBLE2)
+
+#ifndef __ultrix__
+u_int16_t _getshort __P((const uchar_t *));
+u_int32_t _getlong __P((const uchar_t *));
+#endif
+
+/* rename functions so they can be wrapped (see sunw/sunw_wrappers.c */
+#define p_option isc_p_option
+const char *p_option(ulong_t option);
+#define p_secstodate isc_p_secstodate
+char *p_secstodate(ulong_t secs);
+
+/* prevent namespace pollution */
+#define res_protocolnumber __res_protocolnumber
+#define res_servicenumber __res_servicenumber
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PORT_RESOLV_H */
diff --git a/usr/src/lib/libresolv2_joy/include/probe_ipv6 b/usr/src/lib/libresolv2_joy/include/probe_ipv6
new file mode 100755
index 0000000000..371ac96c55
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/probe_ipv6
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Copyright 2003 by Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+set -e
+PATH=/bin:/usr/bin:$PATH; export PATH
+trap "rm -f tmp$$[abc].[oc]" 0
+target=port_ipv6
+new=new_${target}.h
+old=${target}.h
+
+cat > tmp$$a.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct sockaddr_in6 xx;
+EOF
+
+cat > tmp$$b.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct in6_addr xx;
+EOF
+
+cat > tmp$$c.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct sockaddr_in6 xx;
+main() { xx.sin6_scope_id = 0; }
+EOF
+
+cat > ${new} <<EOF
+
+/* This file is automatically generated. Do Not Edit. */
+
+#ifndef ${target}_h
+#define ${target}_h
+
+EOF
+
+if ${CC} -c tmp$$a.c > /dev/null 2>&1
+then
+ echo "#define HAS_INET6_STRUCTS" >> ${new}
+ if ${CC} -c tmp$$b.c > /dev/null 2>&1
+ then
+ :
+ else
+ echo "#define in6_addr in_addr6" >> ${new}
+ fi
+ if ${CC} -c tmp$$c.c > /dev/null 2>&1
+ then
+ echo "#define HAVE_SIN6_SCOPE_ID" >> ${new}
+ else
+ echo "#undef HAVE_SIN6_SCOPE_ID" >> ${new}
+ fi
+else
+ echo "#undef HAS_INET6_STRUCTS" >> ${new}
+fi
+echo >> ${new}
+echo "#endif" >> ${new}
+if [ -f ${old} ]; then
+ if cmp -s ${new} ${old} ; then
+ rm -f ${new}
+ else
+ rm -f ${old}
+ mv ${new} ${old}
+ fi
+else
+ mv ${new} ${old}
+fi
+exit 0
diff --git a/usr/src/lib/libresolv2_joy/include/probe_ipv6.sh b/usr/src/lib/libresolv2_joy/include/probe_ipv6.sh
new file mode 100644
index 0000000000..371ac96c55
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/probe_ipv6.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Copyright 2003 by Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+set -e
+PATH=/bin:/usr/bin:$PATH; export PATH
+trap "rm -f tmp$$[abc].[oc]" 0
+target=port_ipv6
+new=new_${target}.h
+old=${target}.h
+
+cat > tmp$$a.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct sockaddr_in6 xx;
+EOF
+
+cat > tmp$$b.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct in6_addr xx;
+EOF
+
+cat > tmp$$c.c <<EOF
+#include <sys/types.h>
+#include <netinet/in.h>
+struct sockaddr_in6 xx;
+main() { xx.sin6_scope_id = 0; }
+EOF
+
+cat > ${new} <<EOF
+
+/* This file is automatically generated. Do Not Edit. */
+
+#ifndef ${target}_h
+#define ${target}_h
+
+EOF
+
+if ${CC} -c tmp$$a.c > /dev/null 2>&1
+then
+ echo "#define HAS_INET6_STRUCTS" >> ${new}
+ if ${CC} -c tmp$$b.c > /dev/null 2>&1
+ then
+ :
+ else
+ echo "#define in6_addr in_addr6" >> ${new}
+ fi
+ if ${CC} -c tmp$$c.c > /dev/null 2>&1
+ then
+ echo "#define HAVE_SIN6_SCOPE_ID" >> ${new}
+ else
+ echo "#undef HAVE_SIN6_SCOPE_ID" >> ${new}
+ fi
+else
+ echo "#undef HAS_INET6_STRUCTS" >> ${new}
+fi
+echo >> ${new}
+echo "#endif" >> ${new}
+if [ -f ${old} ]; then
+ if cmp -s ${new} ${old} ; then
+ rm -f ${new}
+ else
+ rm -f ${old}
+ mv ${new} ${old}
+ fi
+else
+ mv ${new} ${old}
+fi
+exit 0
diff --git a/usr/src/lib/libresolv2_joy/include/res_update.h b/usr/src/lib/libresolv2_joy/include/res_update.h
new file mode 100644
index 0000000000..0c6967db56
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/res_update.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id: res_update.h,v 1.3 2005/04/27 04:56:15 sra Exp $
+ */
+
+#ifndef __RES_UPDATE_H
+#define __RES_UPDATE_H
+
+/*! \file */
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <isc/list.h>
+#include <resolv_joy.h>
+
+#ifndef ORIGINAL_ISC_CODE
+/* definition of u_int32_t needed on Solaris */
+#include <sys/bitypes.h>
+/* need to rename ns_updrec before we define it here */
+#include "arpa/port_nameser.h"
+#endif /* ORIGINAL_ISC_CODE */
+
+
+/*%
+ * This RR-like structure is particular to UPDATE.
+ */
+struct ns_updrec {
+ LINK(struct ns_updrec) r_link, r_glink;
+ ns_sect r_section; /*%< ZONE/PREREQUISITE/UPDATE */
+ char * r_dname; /*%< owner of the RR */
+ ns_class r_class; /*%< class number */
+ ns_type r_type; /*%< type number */
+ u_int32_t r_ttl; /*%< time to live */
+ u_char * r_data; /*%< rdata fields as text string */
+ u_int r_size; /*%< size of r_data field */
+ int r_opcode; /*%< type of operation */
+ /* following fields for private use by the resolver/server routines */
+ struct databuf *r_dp; /*%< databuf to process */
+ struct databuf *r_deldp; /*%< databuf's deleted/overwritten */
+ u_int r_zone; /*%< zone number on server */
+};
+typedef struct ns_updrec ns_updrec;
+typedef LIST(ns_updrec) ns_updque;
+
+#ifdef ORIGINAL_ISC_CODE
+#define res_mkupdate __res_mkupdate
+#define res_update __res_update
+#define res_mkupdrec __res_mkupdrec
+#define res_freeupdrec __res_freeupdrec
+#define res_nmkupdate __res_nmkupdate
+#define res_nupdate __res_nupdate
+#else
+/* these are renamed in "port_nameser.h" */
+#endif /* ORIGINAL_ISC_CODE */
+
+
+int res_mkupdate __P((ns_updrec *, u_char *, int));
+int res_update __P((ns_updrec *));
+ns_updrec * res_mkupdrec __P((int, const char *, u_int, u_int, u_long));
+void res_freeupdrec __P((ns_updrec *));
+int res_nmkupdate __P((res_state, ns_updrec *, u_char *, int));
+int res_nupdate __P((res_state, ns_updrec *, ns_tsig_key *));
+
+#endif /*__RES_UPDATE_H*/
+
+/*! \file */
diff --git a/usr/src/lib/libresolv2_joy/include/resolv_mt.h b/usr/src/lib/libresolv2_joy/include/resolv_mt.h
new file mode 100644
index 0000000000..500d4d764c
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/resolv_mt.h
@@ -0,0 +1,47 @@
+#ifndef _RESOLV_MT_H
+#define _RESOLV_MT_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv_joy.h>
+
+/* Access functions for the libresolv private interface */
+
+int __res_enable_mt(void);
+int __res_disable_mt(void);
+
+/* Per-thread context */
+
+typedef struct {
+int no_hosts_fallback_private;
+int retry_save;
+int retry_private;
+char inet_nsap_ntoa_tmpbuf[255*3];
+char sym_ntos_unname[20];
+char sym_ntop_unname[20];
+char p_option_nbuf[40];
+char p_time_nbuf[40];
+char precsize_ntoa_retbuf[sizeof "90000000.00"];
+char loc_ntoa_tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+char p_secstodate_output[15];
+} mtctxres_t;
+
+/* Thread-specific data (TSD) */
+
+mtctxres_t *___mtctxres(void);
+#define mtctxres (___mtctxres())
+
+/* Various static data that should be TSD */
+
+#define sym_ntos_unname (mtctxres->sym_ntos_unname)
+#define sym_ntop_unname (mtctxres->sym_ntop_unname)
+#define inet_nsap_ntoa_tmpbuf (mtctxres->inet_nsap_ntoa_tmpbuf)
+#define p_option_nbuf (mtctxres->p_option_nbuf)
+#define p_time_nbuf (mtctxres->p_time_nbuf)
+#define precsize_ntoa_retbuf (mtctxres->precsize_ntoa_retbuf)
+#define loc_ntoa_tmpbuf (mtctxres->loc_ntoa_tmpbuf)
+#define p_secstodate_output (mtctxres->p_secstodate_output)
+
+#endif /* _RESOLV_MT_H */
diff --git a/usr/src/lib/libresolv2_joy/include/sunw_port_after.h b/usr/src/lib/libresolv2_joy/include/sunw_port_after.h
new file mode 100644
index 0000000000..bff64a74c1
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/sunw_port_after.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SUNW_PORT_AFTER_H
+#define _SUNW_PORT_AFTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * rename setnetgrent and endnetgrent which were formerly in a separate irs
+ * shared library. These functions should come from libc.so
+ */
+#define setnetgrent res_setnetgrent
+#ifdef SETNETGRENT_ARGS
+void setnetgrent(SETNETGRENT_ARGS);
+#else
+void setnetgrent(const char *netgroup);
+#endif
+
+#define endnetgrent res_endnetgrent
+void endnetgrent(void);
+
+
+/*
+ * include ports for the public header files. ISC's versions are quite different
+ * from those currently in OpenSolaris.
+ */
+
+#ifdef _RESOLV_JOY_H
+#include <port_resolv.h>
+#endif /* _RESOLV_JOY_H */
+
+#ifdef _NETDB_H
+#include <port_netdb.h>
+#endif /* _NETDB_H */
+
+#ifdef _ARPA_INET_H
+#include <arpa/port_inet.h>
+#endif /* _ARPA_INET_H */
+
+#ifdef _ARPA_NAMESER_H
+#include <arpa/port_nameser.h>
+#endif /* _ARPA_NAMESER_H */
+
+
+#ifdef _ARPA_NAMESER_COMPAT_H
+/* no changes */
+#endif /* _ARPA_NAMESER_COMPAT_H */
+
+/* version-specific defines */
+#include <os_version.h>
+
+/*
+ * Prior to 2.6, Solaris needs a prototype for gethostname().
+ */
+#if (OS_MAJOR == 5 && OS_MINOR < 6)
+extern int gethostname(char *, size_t);
+#endif
+/*
+ * gethostid() was not available until 2.5
+ * setsockopt(SO_REUSEADDR) fails on unix domain sockets before 2.5
+ * use ioctl(FIONBIO) rather than fcntl() calls to set/clear non-blocking i/o.
+ */
+#if (OS_MAJOR == 5 && OS_MINOR < 5)
+#define GET_HOST_ID_MISSING
+#define NO_UNIX_REUSEADDR
+#define USE_FIONBIO_IOCTL
+#endif
+
+#if (OS_MAJOR == 5 && OS_MINOR < 11)
+#define NEED_STRSEP
+extern char *strsep(char **, const char *);
+#endif
+
+
+/*
+ * Solaris 2.5 and later have getrlimit(), setrlimit() and getrusage().
+ */
+#if (OS_MAJOR > 5 || (OS_MAJOR == 5 && OS_MINOR >= 5))
+#include <sys/resource.h>
+#define HAVE_GETRUSAGE
+#define RLIMIT_TYPE rlim_t
+#define RLIMIT_FILE_INFINITY
+#endif
+
+/* the default syslog facility of named/lwresd. */
+#ifndef ISC_FACILITY
+#define ISC_FACILITY LOG_DAEMON
+#endif
+
+
+/*
+ * Solaris 8 has if_nametoindex().
+ */
+#if (OS_MAJOR > 5 || (OS_MAJOR == 5 && OS_MINOR >= 8))
+#define USE_IFNAMELINKID
+#endif
+
+#undef ALIGN
+#if (OS_MAJOR == 5 && OS_MINOR > 8)
+#define ALIGN(x) (((uintptr_t)(x) + (sizeof (char *) - 1UL)) & \
+ ~(sizeof (char *) - 1UL))
+#else
+#define ALIGN(x) (((unsigned long)(x) + (sizeof (char *) - 1UL)) & \
+ ~(sizeof (char *) - 1UL))
+#endif
+
+#if (OS_MAJOR == 5 && OS_MINOR < 5)
+#ifndef USE_FIONBIO_IOCTL
+#define USE_FIONBIO_IOCTL 1
+#endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SUNW_PORT_AFTER_H */
diff --git a/usr/src/lib/libresolv2_joy/include/sunw_port_before.h b/usr/src/lib/libresolv2_joy/include/sunw_port_before.h
new file mode 100644
index 0000000000..776e311fcc
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/sunw_port_before.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SUNW_PORT_BEFORE_H
+#define _SUNW_PORT_BEFORE_H
+
+#ifdef SUNW_OPTIONS
+#include <conf/sunoptions.h>
+#endif
+
+/* version-specific defines */
+#include <os_version.h>
+#if (OS_MAJOR == 5 && OS_MINOR < 6)
+#ifndef SOLARIS_BITTYPES
+#define NEED_SOLARIS_BITTYPES 1
+#endif
+#endif
+
+#if (OS_MAJOR == 5 && OS_MINOR < 5)
+#undef HAS_PTHREADS
+#else
+#define HAS_PTHREADS
+#endif
+
+#if defined(HAS_PTHREADS) && defined(_REENTRANT)
+#define DO_PTHREADS
+#endif
+
+/*
+ * need these if we are using public versions of nameser.h, resolv.h, and
+ * inet.h
+ */
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+#include <sys/bitypes.h>
+#else
+#include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+
+#endif /* _SUNW_PORT_BEFORE_H */
diff --git a/usr/src/lib/libresolv2_joy/include/sys/bitypes.h b/usr/src/lib/libresolv2_joy/include/sys/bitypes.h
new file mode 100644
index 0000000000..54fb42bad7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/sys/bitypes.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1998, 1999, 2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: bitypes.h,v 1.7 2008/11/14 02:54:35 tbox Exp $ */
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+ /*
+ * Basic integral types. Omit the typedef if
+ * not possible for a machine/compiler combination.
+ */
+
+#ifdef NEED_SOLARIS_BITTYPES
+ typedef /*signed*/ char int8_t;
+ typedef short int16_t;
+ typedef int int32_t;
+#endif
+ typedef unsigned char u_int8_t;
+ typedef unsigned short u_int16_t;
+ typedef unsigned int u_int32_t;
+
+#endif /* __BIT_TYPES_DEFINED__ */
diff --git a/usr/src/lib/libresolv2_joy/include/sys/cdefs.h b/usr/src/lib/libresolv2_joy/include/sys/cdefs.h
new file mode 100644
index 0000000000..67aac00cc7
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/include/sys/cdefs.h
@@ -0,0 +1,144 @@
+/*
+ * ++Copyright++ 1991, 1993
+ * -
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * @(#)cdefs.h 8.1 (Berkeley) 6/2/93
+ * $Id: cdefs.h,v 1.2 2004/07/19 05:54:07 marka Exp $
+ */
+
+#ifndef _CDEFS_H_
+#define _CDEFS_H_
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
+ * in between its arguments. __CONCAT can also concatenate double-quoted
+ * strings produced by the __STRING macro, but this only works with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#define __CONCAT(x,y) x ## y
+#define __STRING(x) #x
+
+#define __const const /* define reserved names to standard */
+#define __signed signed
+#define __volatile volatile
+#if defined(__cplusplus)
+#define __inline inline /* convert to C++ keyword */
+#else
+#ifndef __GNUC__
+#define __inline /* delete GCC keyword */
+#endif /* !__GNUC__ */
+#endif /* !__cplusplus */
+
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+
+#ifndef __GNUC__
+#define __const /* delete pseudo-ANSI C keywords */
+#define __inline
+#define __signed
+#define __volatile
+/*
+ * In non-ANSI C environments, new programs will want ANSI-only C keywords
+ * deleted from the program and old programs will want them left alone.
+ * When using a compiler other than gcc, programs using the ANSI C keywords
+ * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
+ * When using "gcc -traditional", we assume that this is the intent; if
+ * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
+ */
+#ifndef NO_ANSI_KEYWORDS
+#define const /* delete ANSI C keywords */
+#define inline
+#define signed
+#define volatile
+#endif
+#endif /* !__GNUC__ */
+#endif /* !(__STDC__ || __cplusplus) */
+
+/*
+ * GCC1 and some versions of GCC2 declare dead (non-returning) and
+ * pure (no side effects) functions using "volatile" and "const";
+ * unfortunately, these then cause warnings under "-ansi -pedantic".
+ * GCC2 uses a new, peculiar __attribute__((attrs)) style. All of
+ * these work for GNU C++ (modulo a slight glitch in the C++ grammar
+ * in the distribution version of 2.5.5).
+ */
+#if !defined(__GNUC__) || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define __dead __volatile
+#define __pure __const
+#endif
+#endif
+
+/* Delete pseudo-keywords wherever they are not available or needed. */
+#ifndef __dead
+#define __dead
+#define __pure
+#endif
+
+#endif /* !_CDEFS_H_ */
diff --git a/usr/src/lib/libresolv2_joy/sparc/Makefile b/usr/src/lib/libresolv2_joy/sparc/Makefile
new file mode 100644
index 0000000000..a333224278
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libresolv2_joy/sparcv9/Makefile b/usr/src/lib/libresolv2_joy/sparcv9/Makefile
new file mode 100644
index 0000000000..ceed393e0d
--- /dev/null
+++ b/usr/src/lib/libresolv2_joy/sparcv9/Makefile
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+# With the adition of BIND 8.3.3, the symbol table for 64 bit went over
+# the limit for Kpic, so we've added -KPIC here, for just the 64 bit
+# library. This avoids compiling the 32-bit library with PIC unnecessarily.
+
+sparcv9_C_PICFLAGS = -K PIC
+sparcv9_CC_PICFLAGS = -KPIC
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libscf/inc/libscf.h b/usr/src/lib/libscf/inc/libscf.h
index c72c1b479c..f4502b7f14 100644
--- a/usr/src/lib/libscf/inc/libscf.h
+++ b/usr/src/lib/libscf/inc/libscf.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2016 RackTop Systems.
*/
@@ -862,8 +863,13 @@ int smf_notify_del_params(const char *, const char *, int32_t);
/*
* SMF exit status definitions
+ *
+ * The SMF_EXIT_NODAEMON exit status should be used when a method does not
+ * need to run any persistent process. This indicates success, abandons the
+ * contract, and allows dependencies to be met.
*/
#define SMF_EXIT_OK 0
+#define SMF_EXIT_NODAEMON 94
#define SMF_EXIT_ERR_FATAL 95
#define SMF_EXIT_ERR_CONFIG 96
#define SMF_EXIT_MON_DEGRADE 97
diff --git a/usr/src/lib/libsff/Makefile b/usr/src/lib/libsff/Makefile
new file mode 100644
index 0000000000..39c13c30bf
--- /dev/null
+++ b/usr/src/lib/libsff/Makefile
@@ -0,0 +1,44 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 Joyent, Inc.
+#
+
+include ../Makefile.lib
+
+HDRS = libsff.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS) $(VARPD_MAPFILES) install_h
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libsff/Makefile.com b/usr/src/lib/libsff/Makefile.com
new file mode 100644
index 0000000000..dab4bfbca3
--- /dev/null
+++ b/usr/src/lib/libsff/Makefile.com
@@ -0,0 +1,34 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 Joyent, Inc. All rights reserved.
+#
+
+LIBRARY = libsff.a
+VERS = .1
+OBJECTS = libsff.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lnvpair
+CPPFLAGS += -I../common
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libsff/amd64/Makefile b/usr/src/lib/libsff/amd64/Makefile
new file mode 100644
index 0000000000..4d3cfa1f81
--- /dev/null
+++ b/usr/src/lib/libsff/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libsff/common/libsff.c b/usr/src/lib/libsff/common/libsff.c
new file mode 100644
index 0000000000..cd0a1228a6
--- /dev/null
+++ b/usr/src/lib/libsff/common/libsff.c
@@ -0,0 +1,1412 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+/*
+ * Parse raw SFF data into an nvlist that can be processed by users, providing
+ * them with what can be printable strings. At the moment, we handle the
+ * majority of parsing page 0xa0 based on SFF 8472 (thus covering INF-8074 and
+ * friends) and SFF 8636 (thus covering SFF-8436 and friends). Interfaces that
+ * parse data into logical structures may be useful to add when considering
+ * monitoring data in page 0xa2.
+ *
+ * When parsing, we try to make sure that the user has supplied, or at least
+ * thinks they have supplied, a buffer of sufficient length. The general design
+ * is that we require the buffer to be large enough to cover all of the offsets
+ * that we care about. If the buffer isn't this large, then we leave it be.
+ *
+ * This library is private and subject to change at any time.
+ */
+
+#include <assert.h>
+#include <strings.h>
+#include <libsff.h>
+#include <errno.h>
+
+#include "sff.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/*
+ * Maximum size of a string buffer while parsing.
+ */
+#define SFP_STRBUF 128
+
+/*
+ * Minimum length of the buffer we require to parse the SFP data.
+ */
+#define SFP_MIN_LEN_8472 96
+#define SFP_MIN_LEN_8636 224
+
+/*
+ * This table is derived from SFF 8024 Section 4.1, Table 4-1.
+ */
+static const char *sff_8024_id_strs[SFF_8024_NIDS] = {
+ "Unknown or Unspecified",
+ "GBIC",
+ "Module/connector soldered to motherboard",
+ "SFP/SFP+/SFP28",
+ "300 pin XBI",
+ "XENPAK",
+ "XFP",
+ "XFF",
+ "XFP-E",
+ "XPAK",
+ "X2",
+ "DWDM-SFP/SFP+ (not using SFF-8472)",
+ "QSFP",
+ "QSFP+ or later",
+ "CXP or later",
+ "Shielded Mini Multilane HD 4X",
+ "Shielded Mini Multilane HD 8X",
+ "QSFP28 or later",
+ "CXP2 (aka CXP28) or later",
+ "CDFP (Style 1/Style2)",
+ "Shielded Mini Multilane HD 4X Fanout Cable",
+ "Shielded Mini Multilane HD 8X Fanout Cable",
+ "CDFP (Style 3)",
+ "microQSFP"
+};
+
+/*
+ * The set of values used for the encoding depends on whether we're a basic SFP
+ * device or not. The values are inconsistent between SFP and QSFP based
+ * devices.
+ *
+ * This table is derived from SFF 8024 r3.9 Table 4-2.
+ */
+#define SFF_8024_NENCS 9
+static const char *sff_8024_enc_sfp[] = {
+ "Unspecified",
+ "8B/10B",
+ "4B/5B",
+ "NRZ",
+ "Manchester",
+ "SONET Scrambled",
+ "64B/66B",
+ "256B/257B",
+ "PAM4"
+};
+
+static const char *sff_8024_enc_qsfp[] = {
+ "Unspecified",
+ "8B/10B",
+ "4B/5B",
+ "NRZ",
+ "SONET Scrambled",
+ "64B/66B",
+ "Manchester",
+ "256B/257B",
+ "PAM4"
+};
+
+/*
+ * This table is derived from SFF 8024 r3.9 Section 4.4.
+ */
+#define SFF_8024_EXT_SPEC_NENTRIES 27
+static const char *sff_8024_ext_spec[] = {
+ "Unspecified",
+ "100G AOC or 25GAUI C2M AOC",
+ "100GBASE-SR4 or 25GBASE-SR",
+ "100GBASE-LR4 or 25GBASE-LR",
+ "100GBASE-ER4 or 25GBASE-ER",
+ "100GBASE-SR10",
+ "100G CWDM4",
+ "100G PSM4 Parallel SMF",
+ "100G ACC or 25GAUI C2M ACC",
+ "Obsolete",
+ "Reserved",
+ "100GBASE-CR4 or 25GBASE-CR CA-L",
+ "25GBASE-CR CA-S",
+ "25GBASE-CR CA-N",
+ "Reserved",
+ "Reserved",
+ "40GBASE-ER4",
+ "4 x 10GBASE-SR",
+ "40G PSM4 Parallel SMF",
+ "G959.1 profile P1I1-2D1",
+ "G959.1 profile P1S1-2D2",
+ "G959.1 profile P1L1-2D2",
+ "10GBASE-T with SFI electrical interface",
+ "100G CLR4",
+ "100G AOC or 25GAUI C2M AOC",
+ "100G ACC or 25GAUI C2M ACC",
+ "100GE-DWDM2"
+};
+
+typedef struct sff_pair {
+ uint_t sp_val;
+ const char *sp_name;
+} sff_pair_t;
+
+/*
+ * This table is derived from SFF 8024 r3.9 Section 4.3.
+ */
+static sff_pair_t sff_8024_connectors[] = {
+ { 0x00, "Unknown" },
+ { 0x01, "SC (Subscriber Connector)" },
+ { 0x02, "Fibre Channel Style 1 copper connector" },
+ { 0x03, "Fibre Channel Style 2 copper connector" },
+ { 0x04, "BNC/TNC (Bayonet/Threaded Neill-Concelman)" },
+ { 0x05, "Fibre Channel coax headers" },
+ { 0x06, "Fiber Jack" },
+ { 0x07, "LC (Lucent Connector)" },
+ { 0x08, "MT-RJ (Mechanical Transfer - Registered Jack)" },
+ { 0x09, "MU (Multiple Optical)" },
+ { 0x0A, "SG" },
+ { 0x0B, "Optical Pigtail" },
+ { 0x0C, "MPO 1x12 (Multifiber Parallel Optic)" },
+ { 0x0D, "MPO 2x16" },
+ { 0x20, "HSSDC II (High Speed Serial Data Connector)" },
+ { 0x21, "Copper pigtail" },
+ { 0x22, "RJ45 (Registered Jack)" },
+ { 0x23, "No separable connector" },
+ { 0x24, "MXC 2x16" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_10GETH_MASK 0xf0
+static sff_pair_t sff_8472_comp_10geth[] = {
+ { 0x80, "10G Base-ER" },
+ { 0x40, "10G Base-LRM" },
+ { 0x20, "10G Base-LR" },
+ { 0x10, "10G Base-SR" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_IB_MASK 0x0f
+static sff_pair_t sff_8472_comp_ib[] = {
+ { 0x08, "1X SX" },
+ { 0x04, "1X LX" },
+ { 0x02, "1X Copper Active" },
+ { 0x01, "1X Copper Passive" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_ESCON_MASK 0xc0
+static sff_pair_t sff_8472_comp_escon[] = {
+ { 0x80, "ESCON MMF, 1310nm LED" },
+ { 0x40, "ESCON SMF, 1310nm Laser" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both
+ * bytes 4 and 5. We treat this as a uint16_t with the low byte as byte 4 and
+ * the high byte as byte 5.
+ */
+#define SFF_8472_COMP_SOCON_MASK 0x773f
+static sff_pair_t sff_8472_comp_sonet[] = {
+ { 0x20, "OC-192, short reach" },
+ { 0x10, "SONET reach specifier bit 1" },
+ { 0x08, "ONET reach specifier bit 2" },
+ { 0x04, "OC-48, long reach" },
+ { 0x02, "OC-48, intermediate reach" },
+ { 0x01, "OC-48, short reach" },
+ /* 0x8000 is unallocated */
+ { 0x4000, "OC-12, single mode, long reach" },
+ { 0x2000, "OC-12, single mode, inter. reach" },
+ { 0x1000, "OC-12, short reach" },
+ /* 0x800 is unallocted */
+ { 0x0400, "OC-3, single mode, long reach" },
+ { 0x0200, "OC-3, single mode, inter. reach" },
+ { 0x0100, "OC-3, short reach" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_ETH_MASK 0xff
+static sff_pair_t sff_8472_comp_eth[] = {
+ { 0x80, "BASE-PX" },
+ { 0x40, "BASE-BX10" },
+ { 0x20, "100BASE-FX" },
+ { 0x10, "100BASE-LX/LX10" },
+ { 0x08, "1000BASE-T" },
+ { 0x04, "1000BASE-CX" },
+ { 0x02, "1000BASE-LX" },
+ { 0x01, "1000BASE-SX" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_FCLEN_MASK 0xf8
+static sff_pair_t sff_8472_comp_fclen[] = {
+ { 0x80, "very long distance (V)" },
+ { 0x40, "short distance (S)" },
+ { 0x20, "intermeddiate distance (I)" },
+ { 0x10, "long distance (L)" },
+ { 0x08, "medium distance (M)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3. These values come from both
+ * bytes 7 and 8. We treat this as a uint16_t with the low byte as byte 7 and
+ * the high byte as byte 8.
+ */
+#define SFF_8472_COMP_TECH_MASK 0xf007
+static sff_pair_t sff_8472_comp_tech[] = {
+ { 0x4, "Shortwave laser, linear Rx (SA)" },
+ { 0x2, "Longwave laser (LC)" },
+ { 0x1, "Electrical inter-enclosure (EL)" },
+ { 0x8000, "Electrical intra-enclosure (EL)" },
+ { 0x4000, "Shortwave laser w/o OFC (SN)" },
+ { 0x2000, "Shortwave laser with OFC (SL)" },
+ { 0x1000, "Longwave laser (LL)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_CABLE_MASK 0x0c
+#define SFF_8472_COMP_CABLE_ACTIVE 0x08
+#define SFF_8472_COMP_CABLE_PASSIVE 0x04
+static sff_pair_t sff_8472_comp_cable[] = {
+ { 0x08, "Active Cable" },
+ { 0x04, "Passive Cable" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_MEDIA_MASK 0xfd
+static sff_pair_t sff_8472_comp_media[] = {
+ { 0x80, "Twin Axial Pair (TW)" },
+ { 0x40, "Twisted Pair (TP)" },
+ { 0x20, "Miniature Coax (MI)" },
+ { 0x10, "Video Coax (TV)" },
+ { 0x08, "Multimode, 62.5um (M6)" },
+ { 0x04, "Multimode, 50um (M5, M5E)" },
+ /* 0x02 is Unallocated */
+ { 0x01, "Single Mode (SM)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 5-3.
+ */
+#define SFF_8472_COMP_SPEED_MASK 0xfd
+static sff_pair_t sff_8472_comp_speed[] = {
+ { 0x80, "1200 MBytes/sec" },
+ { 0x40, "800 MBytes/sec" },
+ { 0x20, "1600 MBytes/sec" },
+ { 0x10, "400 MBytes/sec" },
+ { 0x08, "3200 MBytes/sec" },
+ { 0x04, "200 MBytes/sec" },
+ /* 0x02 is Unallocated */
+ { 0x01, "100 MBytes/sec" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 8-1.
+ * Note, only byte 60 is allocated at this time.
+ */
+#define SFF_8472_PCABLE_COMP_MASK 0x3f
+static sff_pair_t sff_8472_pcable_comp[] = {
+ { 0x20, "Reserved for SFF-8461" },
+ { 0x10, "Reserved for SFF-8461" },
+ { 0x08, "Reserved for SFF-8461" },
+ { 0x04, "Reserved for SFF-8461" },
+ { 0x02, "Compliant to FC-PI-4 Appendix H" },
+ { 0x01, "Compliant to SFF-8431 Appendix E" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 8-2.
+ * Note, only byte 60 is allocated at this time.
+ */
+#define SFF_8472_ACABLE_COMP_MASK 0xf
+static sff_pair_t sff_8472_acable_comp[] = {
+ { 0x08, "Compliant to FC-PI-4 Limiting" },
+ { 0x04, "Compliant to SFF-8431 Limiting" },
+ { 0x02, "Compliant to FC-PI-4 Appendix H" },
+ { 0x01, "Compliant to SFF-8431 Appendix" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 8-3.
+ * Note that we combined byte 64 and 65. Byte 64 is the upper bit.
+ */
+#define SFF_8472_OPTION_MASK 0x3ffe
+static sff_pair_t sff_8472_options[] = {
+ { 0x2000, "Power Level 3 Requirement"},
+ { 0x1000, "Paging Implemented"},
+ { 0x0800, "Retimer or CDR implemented"},
+ { 0x0400, "Cooled Transceiver Implemented"},
+ { 0x0200, "Power Level 2 Requirement"},
+ { 0x0100, "Linear Receiver Output Implemented"},
+ { 0x0080, "Receiver decision threshold implemented"},
+ { 0x0040, "Tunable transmitter"},
+ { 0x0020, "RATE_SELECT implemented"},
+ { 0x0010, "TX_DISABLE implemented"},
+ { 0x0008, "TX_FAULT implemented"},
+ { 0x0004, "Rx_LOS inverted"},
+ { 0x0002, "Rx_LOS implemented"},
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 8-6.
+ */
+#define SFF_8472_EXTOPT_MASK 0xfe
+static sff_pair_t sff_8472_extopts[] = {
+ { 0x80, "Alarm/Warning flags implemented" },
+ { 0x40, "Soft TX_DISABLE implemented" },
+ { 0x20, "Soft TX_FAULT implemented" },
+ { 0x10, "Soft RX_LOS implemented" },
+ { 0x08, "Soft RATE_SELECT implemented" },
+ { 0x04, "Application Select implemented" },
+ { 0x02, "Soft Rate Select Control Implemented" },
+ { 0x01, "" },
+};
+
+/*
+ * This is derived from SFF 8472 r12.2 Table 8-8.
+ */
+#define SFF_8472_8472_COMP_NENTRIES 9
+static const char *sff_8472_8472_comp[] = {
+ "Not compliant",
+ "Rev 9.3",
+ "Rev 9.5",
+ "Rev 10.2",
+ "Rev 10.4",
+ "Rev 11.0",
+ "Rev 11.3",
+ "Rev 11.4",
+ "Rev 12.0"
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_10GETH_MASK 0x7f
+static sff_pair_t sff_8636_comp_10geth[] = {
+ { 0x40, "10GBASE-LRM" },
+ { 0x20, "10GBASE-LR" },
+ { 0x10, "10GBASE-SR" },
+ { 0x08, "40GBASE-CR4" },
+ { 0x04, "40GBASE-SR4" },
+ { 0x02, "40GBASE-LR4" },
+ { 0x01, "40G Active Cable (XLPPI)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_SONET_MASK 0x07
+static sff_pair_t sff_8636_comp_sonet[] = {
+ { 0x04, "OC 48, long reach" },
+ { 0x02, "OC 48, intermediate reach" },
+ { 0x01, "OC 48 short reach" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_SAS_MASK 0xf0
+static sff_pair_t sff_8636_comp_sas[] = {
+ { 0x80, "SAS 24.0 Gb/s" },
+ { 0x40, "SAS 12.0 Gb/s" },
+ { 0x20, "SAS 6.0 Gb/s" },
+ { 0x10, "SAS 3.0 Gb/s" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_ETH_MASK 0x0f
+static sff_pair_t sff_8636_comp_eth[] = {
+ { 0x08, "1000BASE-T" },
+ { 0x04, "1000BASE-CX" },
+ { 0x02, "1000BASE-LX" },
+ { 0x01, "1000BASE-SX" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_FCLEN_MASK 0xf8
+static sff_pair_t sff_8636_comp_fclen[] = {
+ { 0x80, "very long distance (V)" },
+ { 0x40, "short distance (S)" },
+ { 0x20, "intermeddiate distance (I)" },
+ { 0x10, "long distance (L)" },
+ { 0x08, "medium distance (M)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_TECH_MASK 0xf003
+static sff_pair_t sff_8636_comp_tech[] = {
+ { 0x2, "Longwave laser (LC)" },
+ { 0x1, "Electrical inter-enclosure (EL)" },
+ { 0x8000, "Electrical intra-enclosure (EL)" },
+ { 0x4000, "Shortwave laser w/o OFC (SN)" },
+ { 0x2000, "Shortwave laser with OFC (SL)" },
+ { 0x1000, "Longwave laser (LL)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_MEDIA_MASK 0xff
+static sff_pair_t sff_8636_comp_media[] = {
+ { 0x80, "Twin Axial Pair (TW)" },
+ { 0x40, "Twisted Pair (TP)" },
+ { 0x20, "Miniature Coax (MI)" },
+ { 0x10, "Video Coax (TV)" },
+ { 0x08, "Multimode, 62.5um (M6)" },
+ { 0x04, "Multimode, 50m (M5)" },
+ { 0x02, "Multimode, 50um (OM3)" },
+ { 0x01, "Single Mode (SM)" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-17.
+ */
+#define SFF_8636_COMP_SPEED_MASK 0xfd
+static sff_pair_t sff_8636_comp_speed[] = {
+ { 0x80, "1200 MBytes/sec" },
+ { 0x40, "800 MBytes/sec" },
+ { 0x20, "1600 MBytes/sec" },
+ { 0x10, "400 MBytes/sec" },
+ { 0x08, "3200 MBytes/sec" },
+ { 0x04, "200 MBytes/sec" },
+ { 0x01, "100 MBytes/sec" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-20.
+ */
+static const char *sff_8636_trans_tech[] = {
+ "850 nm VCSEL",
+ "1310 nm VCSEL",
+ "1550 nm VCSEL",
+ "1310 nm FP",
+ "1310 nm DFB",
+ "1550 nm DFB",
+ "1310 nm EML",
+ "1550 nm EML",
+ "Other / Undefined",
+ "1490 nm DFB",
+ "Copper cable unequalized",
+ "Copper cable passive equalized",
+ "Copper cable, near and far end limiting active equalizers",
+ "Copper cable, far end limiting active equalizers",
+ "Copper cable, near end limiting active equalizers",
+ "Copper cable, linear active equalizers"
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-21.
+ */
+#define SFF_8636_EXTMOD_CODES 0x1f
+static sff_pair_t sff_8636_extmod_codes[] = {
+ { 0x10, "EDR" },
+ { 0x08, "FDR" },
+ { 0x04, "QDR" },
+ { 0x02, "DDR" },
+ { 0x01, "SDR" },
+ { 0x00, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-22. This combines bytes 193-195.
+ * We treat byte 193 as the most significant.
+ */
+#define SFF_8636_OPTION_MASK 0x0ffffe
+static sff_pair_t sff_8636_options[] = {
+ { 0x080000, "TX Input Equalization Auto Adaptive Capable" },
+ { 0x040000, "TX Input Equalization Fixed Programmable" },
+ { 0x020000, "RX Output Emphasis Fixed Programmable Settings" },
+ { 0x010000, "RX Output Amplitude Fixed Programmable Settings" },
+ { 0x008000, "TX CDR On/Off Control implemented" },
+ { 0x004000, "RX CDR On/Off Control implemented" },
+ { 0x002000, "Tx CDR Loss of Lock Flag implemented" },
+ { 0x001000, "Rx CDR Loss of Lock Flag implemented" },
+ { 0x000800, "Rx Squelch Disable implemented" },
+ { 0x000400, "Rx Output Disable capable" },
+ { 0x000200, "Tx Squelch Disable implemented" },
+ { 0x000100, "Tx Squelch implemented" },
+ { 0x000080, "Memory page 02h provided" },
+ { 0x000040, "Memory page 01h provided" },
+ { 0x000020, "Rate Select implemented" },
+ { 0x000010, "Tx_DISABLE implemented" },
+ { 0x000008, "Tx_FAULT implemented" },
+ { 0x000004, "Tx Squelch for Pave" },
+ { 0x000002, "Tx Loss of Signal implemented" },
+ { 0x0, NULL }
+};
+
+/*
+ * This is derived from SFF 8636 r2.7 Table 6-25.
+ */
+#define SFF_8636_ENHANCED_OPTIONS_MASK 0x1c
+static sff_pair_t sff_8636_eopt[] = {
+ { 0x10, "Initialization Complete Flag Implemented" },
+ { 0x08, "Extended Rate Selection Supported" },
+ { 0x04, "Application Select Table Supported" },
+ { 0x0, NULL }
+};
+
+static const char *
+sff_pair_find(uint_t val, sff_pair_t *pairs)
+{
+ while (pairs->sp_name != NULL) {
+ if (val == pairs->sp_val)
+ return (pairs->sp_name);
+ pairs++;
+ }
+
+ return (NULL);
+}
+
+static int
+sff_parse_id(uint8_t id, nvlist_t *nvl)
+{
+ const char *val;
+
+ if (id >= SFF_8024_VENDOR) {
+ val = "Vendor Specific";
+ } else if (id >= SFF_8024_NIDS) {
+ val = "Reserved";
+ } else {
+ val = sff_8024_id_strs[id];
+ }
+
+ return (nvlist_add_string(nvl, LIBSFF_KEY_IDENTIFIER, val));
+}
+
+static int
+sff_add_unit_string(uint64_t val, uint64_t factor, const char *unit,
+ nvlist_t *nvl, const char *key)
+{
+ char str[SFP_STRBUF];
+
+ val *= factor;
+ (void) snprintf(str, sizeof (str), "%" PRIu64 " %s", val, unit);
+ return (nvlist_add_string(nvl, key, str));
+}
+
+static int
+sff_parse_connector(uint8_t con, nvlist_t *nvl)
+{
+ const char *val;
+
+ if (con >= 0x80) {
+ val = "Vendor Specific";
+ } else {
+ if ((val = sff_pair_find(con, sff_8024_connectors)) == NULL)
+ val = "Reserved";
+ }
+
+ return (nvlist_add_string(nvl, LIBSFF_KEY_CONNECTOR, val));
+}
+
+/*
+ * Many of the values in the specifications are bitfields of which one or more
+ * bits may be set. We represent that as an array of strings. One entry will be
+ * added for each set bit that's found in pairs.
+ */
+static int
+sff_gather_bitfield(uint32_t value, const char *name, sff_pair_t *pairs,
+ nvlist_t *nvl)
+{
+ uint32_t i;
+ const char *vals[32];
+ uint_t count;
+
+ count = 0;
+ for (i = 0; i < 32; i++) {
+ uint32_t bit;
+ const char *str;
+
+ bit = 1 << i;
+ if ((bit & value) == 0)
+ continue;
+
+ str = sff_pair_find(bit, pairs);
+ if (str != NULL) {
+ vals[count++] = str;
+ }
+ }
+
+ if (count == 0)
+ return (0);
+
+ /*
+ * The nvlist routines don't touch the array, so we end up lying about
+ * the type of data so that we can avoid a rash of additional
+ * allocations and strdups.
+ */
+ return (nvlist_add_string_array(nvl, name, (char **)vals, count));
+}
+
+static int
+sff_parse_compliance(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+ uint16_t v;
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_10GE] &
+ SFF_8472_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE,
+ sff_8472_comp_10geth, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_IB] &
+ SFF_8472_COMP_IB_MASK, LIBSFF_KEY_COMPLIANCE_IB,
+ sff_8472_comp_ib, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ESCON] &
+ SFF_8472_COMP_ESCON_MASK, LIBSFF_KEY_COMPLIANCE_ESCON,
+ sff_8472_comp_escon, nvl)) != 0)
+ return (ret);
+
+ v = buf[SFF_8472_COMPLIANCE_SONET_LOW] |
+ (buf[SFF_8472_COMPLIANCE_SONET_HIGH] << 8);
+ if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_SOCON_MASK,
+ LIBSFF_KEY_COMPLIANCE_SONET, sff_8472_comp_sonet, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_ETHERNET] &
+ SFF_8472_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE,
+ sff_8472_comp_eth, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FCLEN] &
+ SFF_8472_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN,
+ sff_8472_comp_fclen, nvl)) != 0)
+ return (ret);
+
+ v = buf[SFF_8472_COMPLIANCE_FC_LOW] |
+ (buf[SFF_8472_COMPLIANCE_FC_HIGH] << 8);
+ if ((ret = sff_gather_bitfield(v & SFF_8472_COMP_TECH_MASK,
+ LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8472_comp_tech, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_SFP] &
+ SFF_8472_COMP_CABLE_MASK, LIBSFF_KEY_COMPLIANCE_SFP,
+ sff_8472_comp_cable, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_MEDIA] &
+ SFF_8472_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA,
+ sff_8472_comp_media, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_COMPLIANCE_FC_SPEED] &
+ SFF_8472_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED,
+ sff_8472_comp_speed, nvl)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+static int
+sff_parse_encoding(uint8_t val, nvlist_t *nvl, boolean_t sfp)
+{
+ const char *str;
+ if (val >= SFF_8024_NENCS) {
+ str = "Reserved";
+ } else if (sfp) {
+ str = sff_8024_enc_sfp[val];
+ } else {
+ str = sff_8024_enc_qsfp[val];
+ }
+
+ return (nvlist_add_string(nvl, LIBSFF_KEY_ENCODING, str));
+}
+
+static int
+sff_parse_br(const uint8_t *buf, nvlist_t *nvl)
+{
+ if (buf[SFF_8472_BR_NOMINAL] == 0xff) {
+ int ret;
+ if ((ret = sff_add_unit_string(buf[SFF_8472_BR_MAX],
+ SFF_8472_BR_MAX_FACTOR, "MBd", nvl,
+ LIBSFF_KEY_BR_MAX)) != 0)
+ return (ret);
+ return (sff_add_unit_string(buf[SFF_8472_BR_MIN],
+ SFF_8472_BR_MIN_FACTOR, "MBd", nvl, LIBSFF_KEY_BR_MIN));
+ } else {
+ return (sff_add_unit_string(buf[SFF_8472_BR_NOMINAL],
+ SFF_8472_BR_NOMINAL_FACTOR, "MBd", nvl,
+ LIBSFF_KEY_BR_NOMINAL));
+ }
+}
+
+static int
+sff_parse_lengths(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+
+ if (buf[SFF_8472_LENGTH_SMF_KM] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF_KM],
+ SFF_8472_LENGTH_SMF_KM_FACTOR, "km", nvl,
+ LIBSFF_KEY_LENGTH_SMF_KM)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8472_LENGTH_SMF] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_SMF],
+ SFF_8472_LENGTH_SMF_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_SMF)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8472_LENGTH_50UM] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_50UM],
+ SFF_8472_LENGTH_50UM_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM2)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8472_LENGTH_62UM] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_62UM],
+ SFF_8472_LENGTH_62UM_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM1)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8472_LENGTH_COPPER] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_COPPER],
+ SFF_8472_LENGTH_COPPER_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_COPPER)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8472_LENGTH_OM3] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8472_LENGTH_OM3],
+ SFF_8472_LENGTH_OM3_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM3)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+/*
+ * Strings in the SFF specification are written into fixed sized buffers. The
+ * strings are padded to the right with spaces (ASCII 0x20) and there is no NUL
+ * character like in a standard C string. While the string is padded with
+ * spaces, spaces may appear in the middle of the string and should not be
+ * confused as padding.
+ */
+static int
+sff_parse_string(const uint8_t *buf, uint_t start, uint_t len,
+ const char *field, nvlist_t *nvl)
+{
+ uint_t i;
+ char strbuf[SFP_STRBUF];
+
+ assert(len < sizeof (strbuf));
+ strbuf[0] = '\0';
+ while (len > 0) {
+ if (buf[start + len - 1] != ' ')
+ break;
+ len--;
+ }
+ if (len == 0)
+ return (0);
+
+ /*
+ * This is supposed to be 7-bit printable ASCII. If we find any
+ * characters that aren't, don't include this string.
+ */
+ for (i = 0; i < len; i++) {
+ if (buf[start + i] < ' ' || buf[start + i] > '~') {
+ return (0);
+ }
+ }
+ bcopy(&buf[start], strbuf, len);
+ strbuf[len] = '\0';
+
+ return (nvlist_add_string(nvl, field, strbuf));
+}
+
+static int
+sff_parse_optical(const uint8_t *buf, nvlist_t *nvl)
+{
+ /*
+ * The value in byte 8 determines whether we interpret this as
+ * describing aspects of a copper device or if it describes the
+ * wavelength.
+ */
+ if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_PASSIVE) {
+ return (sff_gather_bitfield(buf[SFF_8472_PASSIVE_SPEC] &
+ SFF_8472_PCABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_PASSIVE,
+ sff_8472_pcable_comp, nvl));
+ } else if (buf[SFF_8472_COMPLIANCE_SFP] & SFF_8472_COMP_CABLE_ACTIVE) {
+ return (sff_gather_bitfield(buf[SFF_8472_ACTIVE_SPEC] &
+ SFF_8472_ACABLE_COMP_MASK, LIBSFF_KEY_COMPLIANCE_ACTIVE,
+ sff_8472_acable_comp, nvl));
+
+ } else {
+ uint16_t val = (buf[SFF_8472_WAVELENGTH_HI] << 8) |
+ buf[SFF_8472_WAVELENGTH_LOW];
+
+ return (sff_add_unit_string(val, SFF_8472_WAVELENGTH_FACTOR,
+ "nm", nvl, LIBSFF_KEY_WAVELENGTH));
+ }
+}
+
+static int
+sff_parse_options(const uint8_t *buf, nvlist_t *nvl)
+{
+ uint16_t val;
+
+ val = (buf[SFF_8472_OPTIONS_HI] << 8) | buf[SFF_8472_OPTIONS_LOW];
+ return (sff_gather_bitfield(val & SFF_8472_OPTION_MASK,
+ LIBSFF_KEY_OPTIONS, sff_8472_options, nvl));
+}
+
+static int
+sff_parse_8472_comp(uint8_t val, nvlist_t *nvl)
+{
+ const char *str;
+
+ if (val >= SFF_8472_8472_COMP_NENTRIES) {
+ str = "Unallocated";
+ } else {
+ str = sff_8472_8472_comp[val];
+ }
+
+ return (nvlist_add_string(nvl, LIBSFF_KEY_COMPLIANCE_8472, str));
+}
+
+/*
+ * Parse an SFP that is either based on INF 8074 or SFF 8472. These are GBIC,
+ * SFP, SFP+, and SFP28 based devices.
+ *
+ * The SFP parsing into an nvlist_t is incomplete. At the moment we're not
+ * parsing the following pieces from SFF 8472 page 0xa0:
+ *
+ * o Rate Selection Logic
+ * o Diagnostic Monitoring Type
+ */
+static int
+sff_parse_sfp(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+
+ if ((ret = sff_parse_id(buf[SFF_8472_IDENTIFIER], nvl)) != 0)
+ return (ret);
+
+ /*
+ * The extended identifier is derived from SFF 8472, Table 5-2. It
+ * generally is just the value 4. The other values are not well defined.
+ */
+ if ((ret = nvlist_add_uint8(nvl, LIBSFF_KEY_8472_EXT_IDENTIFIER,
+ buf[SFF_8472_EXT_IDENTIFER])) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_connector(buf[SFF_8472_CONNECTOR], nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_compliance(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_encoding(buf[SFF_8472_ENCODING], nvl,
+ B_TRUE)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_br(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_lengths(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8472_VENDOR, SFF_8472_VENDOR_LEN,
+ LIBSFF_KEY_VENDOR, nvl)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI,
+ (uchar_t *)&buf[SFF_8472_OUI], SFF_8472_OUI_LEN)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_PN,
+ SFF_8472_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_REV,
+ SFF_8472_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_optical(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_options(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8472_VENDOR_SN,
+ SFF_8472_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8472_DATE_CODE,
+ SFF_8472_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8472_ENHANCED_OPTIONS] &
+ SFF_8472_EXTOPT_MASK, LIBSFF_KEY_EXTENDED_OPTIONS,
+ sff_8472_extopts, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_8472_comp(buf[SFF_8472_SFF_8472_COMPLIANCE],
+ nvl)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+static int
+sff_qsfp_parse_compliance(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+ uint16_t fc_val;
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_10GBEP] &
+ SFF_8636_COMP_10GETH_MASK, LIBSFF_KEY_COMPLIANCE_10GBE,
+ sff_8636_comp_10geth, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SONET] &
+ SFF_8636_COMP_SONET_MASK, LIBSFF_KEY_COMPLIANCE_SONET,
+ sff_8636_comp_sonet, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_SAS] &
+ SFF_8636_COMP_SAS_MASK, LIBSFF_KEY_COMPLIANCE_SAS,
+ sff_8636_comp_sas, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_ETHERNET] &
+ SFF_8636_COMP_ETH_MASK, LIBSFF_KEY_COMPLIANCE_GBE,
+ sff_8636_comp_eth, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FCLEN] &
+ SFF_8636_COMP_FCLEN_MASK, LIBSFF_KEY_COMPLIANCE_FC_LEN,
+ sff_8636_comp_fclen, nvl)) != 0)
+ return (ret);
+
+ fc_val = buf[SFF_8636_COMPLIANCE_FC_LOW] |
+ (buf[SFF_8636_COMPLIANCE_FC_HIGH] << 8);
+ if ((ret = sff_gather_bitfield(fc_val & SFF_8636_COMP_TECH_MASK,
+ LIBSFF_KEY_COMPLIANCE_FC_TECH, sff_8636_comp_tech, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_MEDIA] &
+ SFF_8636_COMP_MEDIA_MASK, LIBSFF_KEY_COMPLIANCE_FC_MEDIA,
+ sff_8636_comp_media, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_COMPLIANCE_FC_SPEED] &
+ SFF_8636_COMP_SPEED_MASK, LIBSFF_KEY_COMPLIANCE_FC_SPEED,
+ sff_8636_comp_speed, nvl)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+static int
+sff_qsfp_parse_br(const uint8_t *buf, nvlist_t *nvl)
+{
+ if (buf[SFF_8636_BR_NOMINAL] == 0xff) {
+ return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL_EXT],
+ SFF_8636_BR_NOMINAL_EXT_FACTOR, "Mbps", nvl,
+ LIBSFF_KEY_BR_NOMINAL));
+ } else {
+ return (sff_add_unit_string(buf[SFF_8636_BR_NOMINAL],
+ SFF_8636_BR_NOMINAL_FACTOR, "Mbps", nvl,
+ LIBSFF_KEY_BR_NOMINAL));
+ }
+}
+
+static int
+sff_qsfp_parse_lengths(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+
+ if (buf[SFF_8636_LENGTH_SMF] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_SMF],
+ SFF_8636_LENGTH_SMF_FACTOR, "km", nvl,
+ LIBSFF_KEY_LENGTH_SMF_KM)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8636_LENGTH_OM3] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM3],
+ SFF_8636_LENGTH_OM3_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM3)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8636_LENGTH_OM2] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM2],
+ SFF_8636_LENGTH_OM2_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM2)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8636_LENGTH_OM1] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_OM1],
+ SFF_8636_LENGTH_OM1_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_OM1)) != 0)
+ return (ret);
+ }
+
+ if (buf[SFF_8636_LENGTH_COPPER] != 0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_LENGTH_COPPER],
+ SFF_8636_LENGTH_COPPER_FACTOR, "m", nvl,
+ LIBSFF_KEY_LENGTH_COPPER)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+sff_qsfp_parse_tech(uint8_t val, nvlist_t *nvl)
+{
+ const char *strs[5];
+
+ strs[0] = sff_8636_trans_tech[(val & 0xf0) >> 4];
+ if (val & 0x08) {
+ strs[1] = "Active Wavelength Control";
+ } else {
+ strs[1] = "No Wavelength Control";
+ }
+
+ if (val & 0x04) {
+ strs[2] = "Cooled Transmitter";
+ } else {
+ strs[2] = "Uncooled Transmitter";
+ }
+
+ if (val & 0x02) {
+ strs[3] = "APD Detector";
+ } else {
+ strs[3] = "Pin Detector";
+ }
+
+ if (val & 0x01) {
+ strs[4] = "Transmitter Tunable";
+ } else {
+ strs[4] = "Transmitter Not Tunable";
+ }
+
+ /*
+ * The nvlist routines don't touch the array, so we end up lying about
+ * the type of data so that we can avoid a rash of additional
+ * allocations and strdups.
+ */
+ return (nvlist_add_string_array(nvl, LIBSFF_KEY_TRAN_TECH,
+ (char **)strs, 5));
+}
+
+static int
+sff_qsfp_parse_copperwave(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+
+ /*
+ * The values that we get depend on whether or not we are a copper
+ * device or not. We can determine this based on the identification
+ * information in the device technology field.
+ */
+ if ((buf[SFF_8636_DEVICE_TECH] & 0xf0) >= 0xa0) {
+ if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_2G], 1,
+ "dB", nvl, LIBSFF_KEY_ATTENUATE_2G)) != 0)
+ return (ret);
+ if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_5G], 1,
+ "dB", nvl, LIBSFF_KEY_ATTENUATE_5G)) != 0)
+ return (ret);
+ if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_7G], 1,
+ "dB", nvl, LIBSFF_KEY_ATTENUATE_7G)) != 0)
+ return (ret);
+ if ((ret = sff_add_unit_string(buf[SFF_8636_ATTENUATE_12G], 1,
+ "dB", nvl, LIBSFF_KEY_ATTENUATE_12G)) != 0)
+ return (ret);
+ } else {
+ uint16_t val;
+ double d;
+ char strbuf[SFP_STRBUF];
+
+ /*
+ * Because we need to divide the units here into doubles, we
+ * can't use the standard unit routine.
+ */
+ val = (buf[SFF_8636_WAVELENGTH_NOMINAL_HI] << 8) |
+ buf[SFF_8636_WAVELENGTH_NOMINAL_LOW];
+ if (val != 0) {
+ d = val / 20.0;
+ (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d);
+ if ((ret = nvlist_add_string(nvl, LIBSFF_KEY_WAVELENGTH,
+ strbuf)) != 0)
+ return (ret);
+ }
+
+ val = (buf[SFF_8636_WAVELENGTH_TOLERANCE_HI] << 8) |
+ buf[SFF_8636_WAVELENGTH_TOLERANCE_LOW];
+ if (val != 0) {
+ d = val / 20.0;
+ (void) snprintf(strbuf, sizeof (strbuf), "%.3lf nm", d);
+ if ((ret = nvlist_add_string(nvl,
+ LIBSFF_KEY_WAVE_TOLERANCE, strbuf)) != 0)
+ return (ret);
+ }
+ }
+
+ return (0);
+}
+
+static int
+sff_qsfp_parse_casetemp(uint8_t val, nvlist_t *nvl)
+{
+ /*
+ * The default temperature per SFF 8636 r2.7 6.3.21 'Maximum Case
+ * Temperature' is 70 C. If the value is zero, we're supposed to assume
+ * it's the default.
+ */
+ if (val == 0)
+ val = 70;
+
+ return (sff_add_unit_string(val, 1, "C", nvl,
+ LIBSFF_KEY_MAX_CASE_TEMP));
+}
+
+static int
+sff_qsfp_parse_extcomp(uint8_t val, nvlist_t *nvl)
+{
+ const char *str;
+
+ if (val >= SFF_8024_EXT_SPEC_NENTRIES) {
+ str = "Reserved";
+ } else {
+ str = sff_8024_ext_spec[val];
+ }
+
+ return (nvlist_add_string(nvl, LIBSFF_KEY_EXT_SPEC, str));
+}
+
+static int
+sff_qsfp_parse_options(const uint8_t *buf, nvlist_t *nvl)
+{
+ uint_t val;
+
+ val = (buf[SFF_8636_OPTIONS_HI] << 16) |
+ (buf[SFF_8636_OPTIONS_MID] << 8) | buf[SFF_8636_OPTIONS_LOW];
+
+ return (sff_gather_bitfield(val & SFF_8636_OPTION_MASK,
+ LIBSFF_KEY_OPTIONS, sff_8636_options, nvl));
+}
+
+static int
+sff_qsfp_parse_diag(uint8_t val, nvlist_t *nvl)
+{
+ const char *buf[2];
+ uint_t count = 1;
+
+ if (val & 0x08) {
+ buf[0] = "Received power measurements: Average Power";
+ } else {
+ buf[0] = "Received power measurements: OMA";
+ }
+
+ if (val & 0x04) {
+ count++;
+ buf[1] = "Transmitter power measurement";
+ }
+
+ /*
+ * The nvlist routines don't touch the array, so we end up lying about
+ * the type of data so that we can avoid a rash of additional
+ * allocations and strdups.
+ */
+ return (nvlist_add_string_array(nvl, LIBSFF_KEY_DIAG_MONITOR,
+ (char **)buf, count));
+}
+
+/*
+ * Parse a QSFP family device that is based on SFF-8436 / SFF-8636. Note that we
+ * ignore the lower half of page 0xa0 at this time and instead focus on the
+ * upper half of page 0xa0 which has identification information.
+ *
+ * For the moment we're not parsing the following fields:
+ *
+ * o Extended Identifier (byte 129)
+ * o Extended Rate Select Compliance (byte 141)
+ */
+static int
+sff_parse_qsfp(const uint8_t *buf, nvlist_t *nvl)
+{
+ int ret;
+
+ if ((ret = sff_parse_id(buf[SFF_8636_IDENTIFIER], nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_connector(buf[SFF_8636_CONNECTOR], nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_compliance(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_encoding(buf[SFF_8636_ENCODING], nvl,
+ B_FALSE)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_br(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_lengths(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_tech(buf[SFF_8636_DEVICE_TECH], nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8636_VENDOR, SFF_8636_VENDOR_LEN,
+ LIBSFF_KEY_VENDOR, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_EXTENDED_MODULE] &
+ SFF_8636_EXTMOD_CODES, LIBSFF_KEY_EXT_MOD_CODES,
+ sff_8636_extmod_codes, nvl)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_byte_array(nvl, LIBSFF_KEY_OUI,
+ (uchar_t *)&buf[SFF_8636_OUI], SFF_8636_OUI_LEN)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_PN,
+ SFF_8636_VENDOR_PN_LEN, LIBSFF_KEY_PART, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_REV,
+ SFF_8636_VENDOR_REV_LEN, LIBSFF_KEY_REVISION, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_copperwave(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_casetemp(buf[SFF_8636_MAX_CASE_TEMP],
+ nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_extcomp(buf[SFF_8636_LINK_CODES], nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_options(buf, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8636_VENDOR_SN,
+ SFF_8636_VENDOR_SN_LEN, LIBSFF_KEY_SERIAL, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_parse_string(buf, SFF_8636_DATE_CODE,
+ SFF_8636_DATE_CODE_LEN, LIBSFF_KEY_DATECODE, nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_qsfp_parse_diag(buf[SFF_8636_DIAG_MONITORING],
+ nvl)) != 0)
+ return (ret);
+
+ if ((ret = sff_gather_bitfield(buf[SFF_8636_ENHANCED_OPTIONS] &
+ SFF_8636_ENHANCED_OPTIONS_MASK, LIBSFF_KEY_ENHANCED_OPTIONS,
+ sff_8636_eopt, nvl)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+int
+libsff_parse(const uint8_t *buf, size_t len, uint_t page, nvlist_t **nvpp)
+{
+ int ret;
+ nvlist_t *nvp = NULL;
+ uint8_t ubuf[256];
+
+ /*
+ * At the moment, we only support page a0.
+ */
+ if (page != 0xa0 || buf == NULL || len == 0 || nvpp == NULL)
+ return (EINVAL);
+
+ *nvpp = NULL;
+
+ /*
+ * Make sure that the library has been given valid data to parse.
+ */
+ if (uucopy(buf, ubuf, MIN(sizeof (ubuf), len)) != 0)
+ return (errno);
+
+ if ((ret = nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0)) != 0)
+ return (ret);
+
+ switch (buf[0]) {
+ case SFF_8024_ID_QSFP:
+ case SFF_8024_ID_QSFP_PLUS:
+ case SFF_8024_ID_QSFP28:
+ /*
+ * For QSFP based products, identification information is spread
+ * across both the top and bottom half of page 0xa0.
+ */
+ if (len < SFP_MIN_LEN_8636) {
+ ret = EINVAL;
+ break;
+ }
+ ret = sff_parse_qsfp(ubuf, nvp);
+ break;
+ default:
+ if (len < SFP_MIN_LEN_8472) {
+ ret = EINVAL;
+ break;
+ }
+ ret = sff_parse_sfp(ubuf, nvp);
+ break;
+ }
+
+ if (ret != 0) {
+ nvlist_free(nvp);
+ } else {
+ *nvpp = nvp;
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libsff/common/libsff.h b/usr/src/lib/libsff/common/libsff.h
new file mode 100644
index 0000000000..04812e478f
--- /dev/null
+++ b/usr/src/lib/libsff/common/libsff.h
@@ -0,0 +1,101 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _LIBSFF_H
+#define _LIBSFF_H
+
+/*
+ * Parse SFF structures and values and return an nvlist_t of keys. This library
+ * is private and subject to change and break compat at any time.
+ */
+
+#include <libnvpair.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int libsff_parse(const uint8_t *, size_t, uint_t, nvlist_t **);
+
+/*
+ * Supported Keys in the resulting nvlist. Not every key will be present in
+ * every SFF compatible device.
+ */
+#define LIBSFF_KEY_IDENTIFIER "Identifier" /* String */
+#define LIBSFF_KEY_CONNECTOR "Connector" /* String */
+#define LIBSFF_KEY_ENCODING "Encoding" /* String */
+#define LIBSFF_KEY_VENDOR "Vendor" /* String */
+#define LIBSFF_KEY_OUI "OUI" /* Byte Array [3] */
+#define LIBSFF_KEY_PART "Part Number" /* String */
+#define LIBSFF_KEY_REVISION "Revision" /* String */
+#define LIBSFF_KEY_SERIAL "Serial Number" /* String */
+#define LIBSFF_KEY_DATECODE "Date Code" /* String */
+#define LIBSFF_KEY_BR_NOMINAL "BR, nominal" /* String */
+#define LIBSFF_KEY_BR_MAX "BR, maximum" /* String */
+#define LIBSFF_KEY_BR_MIN "BR, minimum" /* String */
+#define LIBSFF_KEY_LENGTH_SMF_KM "Length SMF (km)" /* String */
+#define LIBSFF_KEY_LENGTH_SMF "Length SMF (m)" /* String */
+#define LIBSFF_KEY_LENGTH_OM2 "Length 50um OM2" /* String */
+#define LIBSFF_KEY_LENGTH_OM1 "Length 62.5um OM1" /* String */
+#define LIBSFF_KEY_LENGTH_COPPER "Length Copper" /* String */
+#define LIBSFF_KEY_LENGTH_OM3 "Length OM3" /* String */
+#define LIBSFF_KEY_WAVELENGTH "Laser Wavelength" /* String */
+#define LIBSFF_KEY_WAVE_TOLERANCE "Wavelength Tolerance" /* String */
+#define LIBSFF_KEY_OPTIONS "Options" /* String Array */
+#define LIBSFF_KEY_COMPLIANCE_8472 "8472 Compliance" /* String */
+#define LIBSFF_KEY_EXTENDED_OPTIONS "Extended Options" /* String Array */
+#define LIBSFF_KEY_ENHANCED_OPTIONS "Enhanced Options" /* String Array */
+#define LIBSFF_KEY_EXT_MOD_CODES "Extended Module Codes" /* String Array */
+#define LIBSFF_KEY_DIAG_MONITOR "Diagnostic Monitoring" /* String */
+#define LIBSFF_KEY_EXT_SPEC "Extended Specification" /* String */
+#define LIBSFF_KEY_MAX_CASE_TEMP "Maximum Case Temperature" /* String */
+#define LIBSFF_KEY_ATTENUATE_2G "Cable Attenuation at 2.5 GHz" /* String */
+#define LIBSFF_KEY_ATTENUATE_5G "Cable Attenuation at 5.0 GHz" /* String */
+#define LIBSFF_KEY_ATTENUATE_7G "Cable Attenuation at 7.0 GHz" /* String */
+#define LIBSFF_KEY_ATTENUATE_12G "Cable Attenuation at 12.9 GHz" /* String */
+#define LIBSFF_KEY_TRAN_TECH "Transmitter Technology" /* String */
+
+/*
+ * Note, different revisions of the SFF standard have different compliance
+ * values available. We try to use a common set of compliance keys when
+ * possible, even if the values will be different. All entries here are String
+ * Arrays.
+ */
+#define LIBSFF_KEY_COMPLIANCE_10GBE "10G+ Ethernet Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_IB "Infiniband Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_ESCON "ESCON Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_SONET "SONET Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_GBE "Ethernet Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_FC_LEN "Fibre Channel Link Lengths"
+#define LIBSFF_KEY_COMPLIANCE_FC_TECH "Fibre Channel Technology"
+#define LIBSFF_KEY_COMPLIANCE_SFP "SFP+ Cable Technology"
+#define LIBSFF_KEY_COMPLIANCE_FC_MEDIA "Fibre Channel Transmission Media"
+#define LIBSFF_KEY_COMPLIANCE_FC_SPEED "Fibre Channel Speed"
+#define LIBSFF_KEY_COMPLIANCE_SAS "SAS Compliance Codes"
+#define LIBSFF_KEY_COMPLIANCE_ACTIVE "Active Cable Specification Compliance"
+#define LIBSFF_KEY_COMPLIANCE_PASSIVE "Passive Cable Specification Compliance"
+
+
+/*
+ * The following keys have meaning that varies based on the standard.
+ */
+#define LIBSFF_KEY_8472_EXT_IDENTIFIER "Extended Identifier" /* uint8_t */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSFF_H */
diff --git a/usr/src/lib/libsff/common/llib-lsff b/usr/src/lib/libsff/common/llib-lsff
new file mode 100644
index 0000000000..1636a7e1b0
--- /dev/null
+++ b/usr/src/lib/libsff/common/llib-lsff
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libsfp.h>
diff --git a/usr/src/lib/libsff/common/mapfile-vers b/usr/src/lib/libsff/common/mapfile-vers
new file mode 100644
index 0000000000..7e48256f37
--- /dev/null
+++ b/usr/src/lib/libsff/common/mapfile-vers
@@ -0,0 +1,37 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017, Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ libsff_parse;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libsff/common/sff.h b/usr/src/lib/libsff/common/sff.h
new file mode 100644
index 0000000000..d3b64e7fba
--- /dev/null
+++ b/usr/src/lib/libsff/common/sff.h
@@ -0,0 +1,221 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _SFF_H
+#define _SFF_H
+
+/*
+ * Definitions internal to libsfp for various SFF versions. This generally
+ * contains offsets for each byte and its purpose. The meaning of the values are
+ * not generally found in this header.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This table is derived from SFF 8024 Section 4.1, Table 4-1.
+ */
+typedef enum sff_8024_id {
+ SFF_8024_ID_UNKNOWN = 0x00,
+ SFF_8024_ID_GBIC = 0x01,
+ SFF_8024_ID_SOLDERED = 0x02,
+ SFF_8024_ID_SFP = 0x03, /* SFP, SFP+, SFP28 */
+ SFF_8024_ID_XBI = 0x04,
+ SFF_8024_ID_XENPAK = 0x05,
+ SFF_8024_ID_XFP = 0x06,
+ SFF_8024_ID_XFF = 0x07,
+ SFF_8024_ID_XFP_E = 0x08,
+ SFF_8024_ID_XPAK = 0x09,
+ SFF_8024_ID_X2 = 0x0A,
+ SFF_8024_ID_DWDM_SFP = 0x0B,
+ SFF_8024_ID_QSFP = 0x0C,
+ SFF_8024_ID_QSFP_PLUS = 0x0D,
+ SFF_8024_ID_CXP = 0x0E,
+ SFF_8024_ID_SMMHD4X = 0x0F,
+ SFF_8024_ID_SMMHD8X = 0x10,
+ SFF_8024_ID_QSFP28 = 0x11,
+ SFF_8024_ID_CXP2 = 0x12,
+ SFF_8024_ID_CDFP = 0x13,
+ SFF_8024_ID_SMMHD4XF = 0x14,
+ SFF_8024_ID_SMMHD8XF = 0x15,
+ SFF_8024_ID_CDFP3 = 0x16,
+ SFF_8024_ID_MICROQSFP = 0x17,
+ SFF_8024_NIDS = 0x18,
+ SFF_8024_VENDOR = 0x80
+} sff_8024_id_t;
+
+
+/*
+ * Byte offsets for SFF-8472. Note that most of this applies to INF-8074.
+ * Generally speaking, SFF-8472 is a backwards compatible evolution of INF-8074.
+ */
+#define SFF_8472_IDENTIFIER 0
+#define SFF_8472_EXT_IDENTIFER 1
+#define SFF_8472_CONNECTOR 2
+
+/*
+ * Note that several constants overlap here as the offset is used for multiple
+ * purposes.
+ */
+#define SFF_8472_COMPLIANCE_10GE 3
+#define SFF_8472_COMPLIANCE_IB 3
+#define SFF_8472_COMPLIANCE_ESCON 4
+#define SFF_8472_COMPLIANCE_SONET_LOW 4
+#define SFF_8472_COMPLIANCE_SONET_HIGH 5
+#define SFF_8472_COMPLIANCE_ETHERNET 6
+#define SFF_8472_COMPLIANCE_FCLEN 7
+#define SFF_8472_COMPLIANCE_FC_LOW 7
+#define SFF_8472_COMPLIANCE_FC_HIGH 8
+#define SFF_8472_COMPLIANCE_SFP 8
+#define SFF_8472_COMPLIANCE_FC_MEDIA 9
+#define SFF_8472_COMPLIANCE_FC_SPEED 10
+
+#define SFF_8472_ENCODING 11
+#define SFF_8472_BR_NOMINAL 12
+#define SFF_8472_RATE_IDENTIFIER 13
+#define SFF_8472_LENGTH_SMF_KM 14
+#define SFF_8472_LENGTH_SMF 15
+#define SFF_8472_LENGTH_50UM 16
+#define SFF_8472_LENGTH_62UM 17
+#define SFF_8472_LENGTH_COPPER 18
+#define SFF_8472_LENGTH_OM3 19
+
+#define SFF_8472_VENDOR 20
+#define SFF_8472_VENDOR_LEN 16
+#define SFF_8472_TRANSCEIVER 36
+#define SFF_8472_OUI 37
+#define SFF_8472_OUI_LEN 3
+#define SFF_8472_VENDOR_PN 40
+#define SFF_8472_VENDOR_PN_LEN 16
+#define SFF_8472_VENDOR_REV 56
+#define SFF_8472_VENDOR_REV_LEN 4
+
+#define SFF_8472_PASSIVE_SPEC 60
+#define SFF_8472_ACTIVE_SPEC 60
+#define SFF_8472_WAVELENGTH_HI 60
+#define SFF_8472_WAVELENGTH_LOW 61
+
+#define SFF_8472_CC_BASE 63
+
+#define SFF_8472_OPTIONS_HI 64
+#define SFF_8472_OPTIONS_LOW 65
+#define SFF_8472_BR_MAX 66
+#define SFF_8472_BR_MIN 67
+#define SFF_8472_VENDOR_SN 68
+#define SFF_8472_VENDOR_SN_LEN 16
+#define SFF_8472_DATE_CODE 84
+#define SFF_8472_DATE_CODE_LEN 8
+#define SFF_8472_DIAG_MONITORING 92
+#define SFF_8472_ENHANCED_OPTIONS 93
+#define SFF_8472_SFF_8472_COMPLIANCE 94
+
+#define SFF_8472_CC_EXT 95
+#define SFF_8472_VENDOR_SPECIFIC 96
+#define SFF_8472_RESERVED 128
+
+/*
+ * These values are factors by which we should multiple or divide various units.
+ */
+#define SFF_8472_BR_NOMINAL_FACTOR 100
+#define SFF_8472_BR_MAX_FACTOR 250
+#define SFF_8472_BR_MIN_FACTOR 250
+#define SFF_8472_LENGTH_SMF_KM_FACTOR 1
+#define SFF_8472_LENGTH_SMF_FACTOR 100
+#define SFF_8472_LENGTH_50UM_FACTOR 10
+#define SFF_8472_LENGTH_62UM_FACTOR 10
+#define SFF_8472_LENGTH_COPPER_FACTOR 1
+#define SFF_8472_LENGTH_OM3_FACTOR 10
+#define SFF_8472_WAVELENGTH_FACTOR 1
+
+
+/*
+ * SFF 8636 related constants
+ */
+#define SFF_8636_IDENTIFIER 0
+#define SFF_8636_EXT_IDENTIFIER 129
+#define SFF_8636_CONNECTOR 130
+
+#define SFF_8636_COMPLIANCE_10GBEP 131
+#define SFF_8636_COMPLIANCE_SONET 132
+#define SFF_8636_COMPLIANCE_SAS 133
+#define SFF_8636_COMPLIANCE_ETHERNET 134
+#define SFF_8636_COMPLIANCE_FCLEN 135
+#define SFF_8636_COMPLIANCE_FC_LOW 135
+#define SFF_8636_COMPLIANCE_FC_HIGH 136
+#define SFF_8636_COMPLIANCE_FC_MEDIA 137
+#define SFF_8636_COMPLIANCE_FC_SPEED 138
+
+#define SFF_8636_ENCODING 139
+#define SFF_8636_BR_NOMINAL 140
+#define SFF_8636_BR_EXT_RATE_SELECT 141
+#define SFF_8636_LENGTH_SMF 142
+#define SFF_8636_LENGTH_OM3 143
+#define SFF_8636_LENGTH_OM2 144
+#define SFF_8636_LENGTH_OM1 145
+#define SFF_8636_LENGTH_COPPER 146
+#define SFF_8636_DEVICE_TECH 147
+#define SFF_8636_VENDOR 148
+#define SFF_8636_VENDOR_LEN 16
+#define SFF_8636_EXTENDED_MODULE 164
+#define SFF_8636_OUI 165
+#define SFF_8636_OUI_LEN 3
+#define SFF_8636_VENDOR_PN 168
+#define SFF_8636_VENDOR_PN_LEN 16
+#define SFF_8636_VENDOR_REV 184
+#define SFF_8636_VENDOR_REV_LEN 2
+
+#define SFF_8636_ATTENUATE_2G 186
+#define SFF_8636_ATTENUATE_5G 187
+#define SFF_8636_ATTENUATE_7G 188
+#define SFF_8636_ATTENUATE_12G 189
+#define SFF_8636_WAVELENGTH_NOMINAL_HI 186
+#define SFF_8636_WAVELENGTH_NOMINAL_LOW 187
+#define SFF_8636_WAVELENGTH_TOLERANCE_HI 188
+#define SFF_8636_WAVELENGTH_TOLERANCE_LOW 189
+#define SFF_8636_MAX_CASE_TEMP 190
+#define SFF_8636_CC_BASE 191
+
+#define SFF_8636_LINK_CODES 192
+#define SFF_8636_OPTIONS_HI 193
+#define SFF_8636_OPTIONS_MID 194
+#define SFF_8636_OPTIONS_LOW 195
+#define SFF_8636_VENDOR_SN 196
+#define SFF_8636_VENDOR_SN_LEN 16
+#define SFF_8636_DATE_CODE 212
+#define SFF_8636_DATE_CODE_LEN 8
+#define SFF_8636_DIAG_MONITORING 220
+#define SFF_8636_ENHANCED_OPTIONS 221
+#define SFF_8636_BR_NOMINAL_EXT 222
+#define SFF_8636_CC_EXT 223
+#define SFF_866_VENDOR_SPECIFIC 224
+
+/*
+ * SFF 8636 multiplication factors
+ */
+#define SFF_8636_BR_NOMINAL_FACTOR 100
+#define SFF_8636_BR_NOMINAL_EXT_FACTOR 250
+#define SFF_8636_LENGTH_SMF_FACTOR 1
+#define SFF_8636_LENGTH_OM3_FACTOR 2
+#define SFF_8636_LENGTH_OM2_FACTOR 1
+#define SFF_8636_LENGTH_OM1_FACTOR 1
+#define SFF_8636_LENGTH_COPPER_FACTOR 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SFF_H */
diff --git a/usr/src/lib/libsff/i386/Makefile b/usr/src/lib/libsff/i386/Makefile
new file mode 100644
index 0000000000..0a22fa4dc3
--- /dev/null
+++ b/usr/src/lib/libsff/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsff/sparc/Makefile b/usr/src/lib/libsff/sparc/Makefile
new file mode 100644
index 0000000000..0a22fa4dc3
--- /dev/null
+++ b/usr/src/lib/libsff/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c
index 8f1bf6cddf..c2d95210c7 100644
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2014, 2016 by Delphix. All rights reserved.
*/
@@ -2835,9 +2836,16 @@ nfs_init()
ret = initprotofromsmf();
if (ret != SA_OK) {
- (void) printf(dgettext(TEXT_DOMAIN,
- "NFS plugin problem with SMF repository: %s\n"),
- sa_errorstr(ret));
+ /*
+ * This is a workaround. See the comment in
+ * cmd/fs.d/nfs/lib/smfcfg.c for an explanation.
+ */
+ if (getzoneid() == GLOBAL_ZONEID ||
+ ret != SCF_ERROR_NOT_FOUND) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "NFS plugin problem with SMF repository: %s\n"),
+ sa_errorstr(ret));
+ }
ret = SA_OK;
}
add_defaults();
diff --git a/usr/src/lib/libshell/Makefile b/usr/src/lib/libshell/Makefile
index b584728d5f..1cce2316f0 100644
--- a/usr/src/lib/libshell/Makefile
+++ b/usr/src/lib/libshell/Makefile
@@ -64,6 +64,5 @@ $(SUBDIRS): FRC
FRC:
include Makefile.demo
-include Makefile.doc
include ../Makefile.targ
diff --git a/usr/src/lib/libshell/Makefile.doc b/usr/src/lib/libshell/Makefile.doc
deleted file mode 100644
index 5f507d28d9..0000000000
--- a/usr/src/lib/libshell/Makefile.doc
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-
-ROOTDOCDIRBASE= $(ROOT)/usr/share/doc/ksh
-
-DOCFILES= \
- RELEASE \
- README \
- TYPES \
- DESIGN \
- COMPATIBILITY \
- OBSOLETE \
- shell_styleguide.docbook \
- images/tag_bourne.png \
- images/tag_i18n.png \
- images/tag_ksh88.png \
- images/tag_ksh93.png \
- images/tag_ksh.png \
- images/tag_l10n.png \
- images/tag_perf.png \
- images/callouts/1.png \
- images/callouts/2.png \
- images/callouts/3.png \
- images/callouts/4.png \
- images/callouts/5.png \
- images/callouts/6.png \
- images/callouts/7.png \
- images/callouts/8.png \
- images/callouts/9.png \
- images/callouts/10.png
-
-# Documentation rules
-$(ROOTDOCDIRBASE)/%: common/%
- $(INS.file)
-
-$(ROOTDOCDIRBASE)/%: misc/%
- $(INS.file)
-
-ROOTDOCDIRS= \
- $(ROOTDOCDIRBASE) .WAIT \
- $(ROOTDOCDIRBASE)/images .WAIT \
- $(ROOTDOCDIRBASE)/images/callouts
-
-# Generic documentation rules
-DOCFILESRCDIR= common
-ROOTDOCFILES= $(DOCFILES:%=$(ROOTDOCDIRBASE)/%)
-$(ROOTDOCDIRS) := OWNER = root
-$(ROOTDOCDIRS) := GROUP = bin
-$(ROOTDOCDIRS) := DIRMODE = 755
-
-$(ROOTDOCDIRS):
- $(INS.dir)
-
-install: $(ROOTDOCDIRS) .WAIT $(ROOTDOCFILES)
diff --git a/usr/src/lib/libshell/common/COMPATIBILITY b/usr/src/lib/libshell/common/COMPATIBILITY
deleted file mode 100644
index d4d645a99a..0000000000
--- a/usr/src/lib/libshell/common/COMPATIBILITY
+++ /dev/null
@@ -1,134 +0,0 @@
-
- KSH-93 VS. KSH-88
-
-
-The following is a list of known incompatibilities between ksh-93 and ksh-88.
-I have not include cases that are clearly bugs in ksh-88. I also have
-omitted features that are completely upward compatible.
-
-1. Functions, defined with name() with ksh-93 are compatible with
- the POSIX standard, not with ksh-88. No local variables are
- permitted, and there is no separate scope. Functions defined
- with the function name syntax, maintain compatibility.
- This also affects function traces.
-
-2. ! is now a reserved word. As a result, any command by that
- name will no longer work with ksh-93.
-
-3. The -x attribute of alias and typeset -f is no longer
- effective and the ENV file is only read for interactive
- shells. You need to use FPATH to make function definitions
- visible to scripts.
-
-4. A built-in command named command has been added which is
- always found before the PATH search. Any script which uses
- this name as the name of a command (or function) will not
- be compatible.
-
-5. The output format for some built-ins has changed. In particular
- the output format for set, typeset and alias now have single
- quotes around values that have special characters. The output
- for trap without arguments has a format that can be used as input.
-
-6. With ksh-88, a dollar sign ($') followed by a single quote was
- interpreted literally. Now it is an ANSI-C string. You
- must quote the dollar sign to get the previous behavior.
- Also, a $ in front of a " indicates that the string needs
- to be translated for locales other than C or POSIX. The $
- is ignored in the C and POSIX locale.
-
-7. With ksh-88, tilde expansion did not take place inside ${...}.
- with ksh-93, ${foo-~} will cause tilde expansion if foo is
- not set. You need to escape the ~ for the previous behavior.
-
-8. Some changes in the tokenizing rules where made that might
- cause some scripts with previously ambiguous use of quoting
- to produce syntax errors.
-
-9. Programs that rely on specific exit values for the shell,
- (rather than 0 or non-zero) may not be compatible. The
- exit status for many shell failures has been changed.
-
-10. Built-ins in ksh-88 were always executed before looking for
- the command in the PATH variable. This is no longer true.
- Thus, with ksh-93, if you have the current directory first
- in your PATH, and you have a program named test in your
- directory, it will be executed when you type test; the
- built-in version will be run at the point /bin is found
- in your PATH.
-
-11. Some undocumented combinations of argument passing to ksh
- builtins no longer works since ksh-93 is getopts conforming
- with respect to its built-ins. For example, typeset -8i
- previously would work as a synonym for typeset -i8.
-
-12. Command substitution and arithmetic expansion are now performed
- on PS1, PS3, and ENV when they are expanded. Thus, ` and $(
- as part of the value of these variables must be preceded by a \
- to preserve their previous behavior.
-
-13. The ERRNO variable has been dropped.
-
-14. If the file name following a redirection symbol contain pattern
- characters they will only be expanded for interactive shells.
-
-15. The arguments to a dot script will be restored when it completes.
-
-16. The list of tracked aliases is not displayed with alias unless
- the -t option is specified.
-
-17. The POSIX standard requires that test "$arg" have exit status
- of 0, if and only if $arg is null. However, since this breaks
- programs that use test -t, ksh93 treats an explicit test -t
- as if the user had entered test -t 1.
-
-18. The ^T directive of emacs mode has been changed to work the
- way it does in gnu-emacs.
-
-19. ksh-88 allowed unbalanced parenthes within ${name op val} whereas
- ksh-93 does not. Thus, ${foo-(} needs to be written as ${foo-\(}
- which works with both versions.
-
-20. kill -l in ksh-93 lists only the signal names, not their numerical
- values.
-
-21. Local variables defined by typeset are statically scoped in
- ksh93. In ksh88 they were dynamically scoped although this
- behavior was never documented.
-
-22. The value of the variable given to getopts is set to ? when
- the end-of-options is reached to conform to the POSIX standard.
-
-23. Since the POSIX standard requires that octal constants be
- recongnized, doing arithmetic on typeset -Z variables can
- yield different results that with ksh88. Most of these
- differences were eliminated in ksh93o.
-
-24. Starting after ksh93l, If you run ksh name, where name does
- not contain a /, the current directory will be searched
- before doing a path search on name as required by the POSIX
- shell standard.
-
-25. In ksh93, cd - will output the directory that it changes
- to on standard output as required by X/Open. With ksh88,
- this only happened for interactive shells.
-
-26. As an undocumented feature of ksh-88, a leading 0 to an
- assignment of an integer variable caused that variable
- to be treated as unsigned. This behavior was removed
- starting in ksh93p.
-
-27. The getopts builtin in ksh93 requires that optstring contain
- a leading + to allow options to begin with a +.
-
-28. In emacs/gmacs mode, control-v will not display the version when
- the stty lnext character is set to control-v or is unset.
- The sequence escape control-v will display the shell version.
-
-29. In ksh88, DEBUG traps were executed. after each command. In ksh93
- DEBUG traps are exeucted before each command.
-
-30. In ksh88, a redirection to a file name given by an empty string was
- ignored. In ksh93, this is an error.
-I am interested in expanding this list so please let me know if you
-uncover any others.
diff --git a/usr/src/lib/libshell/common/DESIGN b/usr/src/lib/libshell/common/DESIGN
deleted file mode 100644
index c11c0aff1e..0000000000
--- a/usr/src/lib/libshell/common/DESIGN
+++ /dev/null
@@ -1,170 +0,0 @@
-Here is an overview of the source code organization for ksh93.
-
-Directory layout:
-
- The directory include contains header files for ksh93.
- The files nval.h and shell.h are intended to be public
- headers and can be used to add runtime builtin command.
- The remainder are private.
-
- The directory data contains readonly data files for ksh93.
- The man pages for built-ins are in builtins.c rather
- than included as statics with the implementations in the
- bltins directory because some systems don't make static const
- data readonly and we want these to be shared by all running
- shells.
-
- The directory edit contains the code for command line
- editing and history.
-
- The fun directory contains some shell function such as
- pushd, popd, and dirs.
-
- The directory features contains files that are used to generate
- header files in the FEATURE directory. Most of these files
- are in a format that is processed by iffe.
-
- The directory bltins contains code for most of the built-in
- commands. Additional built-in commands are part of libcmd.
-
- The directory sh contains most of the code for ksh93.
-
- The directory tests contains a number of regression tests.
- In most cases, when a bug gets fixed, a test is added to
- one of these files. The regression tests can be run by
- going to this directory and running
- SHELL=shell_path shell_path shtests
- where shell_path is an absolute pathname for the shell to
- be tested.
-
- The top level directory contains the nmake Makefile, a README,
- and several documentation files. The RELEASE file contains
- the list of bug fixes and new features since the original
- ksh93 release. The file COMPATIBILITY is a list of all
- known incompatibilities with ksh88.
-
- The bash_pre_rc.sh is a startup script used when emulating
- bash if the shell is compiled with SHOPT_BASH and the shell
- is invoked as bash. The bash emulation is not complete.
-
-Include directory:
- 1. argnod.h contains the type definitions for command
- nodes, io nodes, argument nodes, and for positional
- parameters.a It defines the prototypes for
- all the positional parameters functions.
- 2. builtins.h contains prototypes for builtins as well
- as symbolic constants that refer to the name-pairs
- that are associated with some of the built-ins.
- It also contains prototypes for many of the strings.
- 3. defs.h is the catch all for all definitions that
- don't fit elsewhere and it includes several other
- headers. It defines a strucuture that contains ksh
- global data, sh, and a structure that contains per
- function data, sh.st.
- 4. edit.h contains definitions that are common to both
- vi and emacs edit modes.
- 5. env.h contains interfaces for creating and modifying
- environment variables.
- 6. fault.h contains prototypes for signal related
- functions and trap and fault handling.
- 7. fcin.h contains macro and function definitions for
- reading from a file or string.
- 8. history.h contains macros and functions definitions
- related to history file processing.
- 9. jobs.h contains the definitions relating to job
- processing and control.
- 10. lexstates.h contains the states associated with
- lexical processing.
- 11. name.h contains the internal definitions related
- to name-value pair processing.
- 12. national.h contains a few I18N definitions, mostly
- obsolete.
- 13. nval.h is the public interface to the name-value
- pair library that is documented with nval.3.
- 14. path.h contains the interface for pathname processing
- and pathname searching.
- 15. shell.h is the public interface for shell functions
- that are documented int shell.3.
- 16. shlex.h contains the lexical token definitions and
- interfaces for lexical analysis.
- 17. shnodes.h contains the definition of the structures
- for each of the parse nodes and flags for the attributes.
- 18. shtable.h contains some interfaces and functions for
- table lookup.
- 19. streval.h contains the interface to the arithmetic
- functions.
- 20. terminal.h is a header file that includes the appropriate
- terminal include.
- 21. test.h contains the definitions for the test and [[...]]
- commands.
- 22. timeout.h contains the define constant for the maximum
- shell timeout.
- 23. ulimit.h includes the appropriate resource header.
- 24. variables.h contains symbolic constants for the built-in
- shell variables.
-
-sh directory:
- 1. args.c contains functions for parsing shell options
- and for processing positional parameters.
- 2. arith.c contains callback functions for the streval.c
- library and the interface to shell arithmetic.
- 3. array.c contains the code for indexed and associative
- arrays.
- 4. bash.h contains code used when compiling with SHOPT_BASH
- to add bash specific features such as shopt.
- 5. defs.c contains the data definitions for global symbols.
- 6. deparse.c contains code to generate shell script from
- a parse tree.
- 7. env.c contains code to add and delete environment variables
- to an environment list.
- 8. expand.c contains code for file name expansion and
- file name generation.
- 9. fault.c contains code for signal processing, trap
- handling and termination.
- 10. fcin.c contains code for reading and writing a character
- at a time from a file or string.
- 11. init.c contains initialization code and callbacks
- for get and set functions for built-in variables.
- 12. io.o contains code for redirections and managing file
- descriptors and file streams.
- 13. jobs.c contains the code for job management.
- 14. lex.c contains the code for the lexical analyzer.
- 15. macro.c contains code for the $ macro expansions, including
- here-documents.
- 16. main.c contains the calls to initialization, profile
- processing and the main evaluation loop as well as
- mail processing.
- 17. name.c contains the name-value pair routines that are
- built on the hash library in libast.
- 18. nvdisc.c contains code related to name-value pair disciplines.
- 19. nvtree.c contains code for compound variables and for
- walking the namespace.
- 20. nvtype.c contains most of the code related to types that
- are created with typeset -T.
- 21. parse.c contains the code for the shell parser.
- 22. path.c contains the code for pathname lookup and
- some path functions. It also contains the code
- that executes commands and scripts.
- 23. pmain.c is just a calls sh_main() so that all of the
- rest of the shell can be in a shared library.
- 24. shcomp.c contains the main program to the shell
- compiler. This program parses a script and creates
- a file that the shell can read containing the parse tree.
- 25. streval.c is an C arithmetic evaluator.
- 26. string.c contains some string related functions.
- 27. subshell.c contains the code to save and restore
- environments so that subshells can run without creating
- a new process.
- 28. suid_exec.c contains the program from running execute
- only and/or setuid/setgid scripts.
- 29. tdump.c contains the code to dump a parse tree into
- a file.
- 30. timers.c contains code for multiple event timeouts.
- 31. trestore contians the code for restoring the parse
- tree from the file created by tdump.
- 32. userinit.c contains a dummy userinit() function.
- This is now obsolete with the new version of sh_main().
- 33. waitevent.c contains the sh_waitnotify function so
- that builtins can handle processing events when the
- shell is waiting for input or for process completion.
- 34. xec.c is the main shell executuion loop.
diff --git a/usr/src/lib/libshell/common/OBSOLETE b/usr/src/lib/libshell/common/OBSOLETE
deleted file mode 100644
index c29cb8bb63..0000000000
--- a/usr/src/lib/libshell/common/OBSOLETE
+++ /dev/null
@@ -1,152 +0,0 @@
-.sp 3
-.tl ''Ksh Features That Are Obsolete in Ksh93''
-.sp 2
-.AL 1
-.LI
-Using a pair of grave accents \^\fB\(ga\fR ... \fB\(ga\fR\^
-for command substition. Use \fB$(\fR ... \fB)\fR instead.
-.LI
-.B FCEDIT
-is an obsolete name for
-the default editor name for the
-.B hist
-command.
-.B FCEDIT
-is not used when
-.B HISTEDIT
-is set. Use
-.B HISTEDIT
-instead.
-.LI
-The newtest (\fB[[\fR ... \fB]]\fR) operator
-\fB\-a\fP \fIfile\fP
-is obsolete. Use
-\fB\-e\fP instead.
-.LI
-The newtest (\fB[[\fR ... \fB]]\fR) operator
-.BR = ,
-as used in
-\fIstring\fP \fB=\fP \fIpattern\fP
-is obsolete. Use
-\fB==\fP instead.
-.LI
-The following obsolete arithmetic comparisons are also permitted:
-.in +5
-.VL 20
-.LI "\fIexp1\fP \fB\-eq\fP \fIexp2\fP"
-True, if
-.I exp1
-is equal to
-.IR exp2 .
-.LI "\fIexp1\fP \fB\-ne\fP \fIexp2\fP"
-True, if
-.I exp1
-is not equal to
-.IR exp2 .
-.LI "\fIexp1\fP \fB\-lt\fP \fIexp2\fP"
-True, if
-.I exp1
-is less than
-.IR exp2 .
-.LI "\fIexp1\fP \fB\-gt\fP \fIexp2\fP"
-True, if
-.I exp1
-is greater than
-.IR exp2 .
-.LI "\fIexp1\fP \fB\-le\fP \fIexp2\fP"
-True, if
-.I exp1
-is less than or equal to
-.IR exp2 .
-.LI "\fIexp1\fP \fB\-ge\fP \fIexp2\fP"
-True, if
-.I exp1
-is greater than or equal to
-.IR exp2 .
-.LE \" End .VL
-.in -5
-.LI
-Using test -t or [ -t ] without specifying the file unit number.
-.LI
-The
-.B \-k
-option to the \fBset\fR builtin is obsolete. It causes
-.I all\^
-variable assignment arguments are placed in the environment,
-even if they occur after the command name.
-The following
-first prints
-.B "a=b c"
-and then
-.BR c :
-There is no alternative.
-.LI
-The obsolete
-.B \-xf
-option of the
-.B typeset
-command allows a function to be exported
-to scripts that are executed without a separate
-invocation of the shell.
-Functions that need to be defined across separate
-invocations of the shell should
-be placed in a directory and the
-.B FPATH
-variable should contains the name of this directory.
-They may also
-be specified in the
-.B ENV
-file with the
-.B \-xf
-option of
-.BR typeset .
-.LI
-The shell environment variable
-.B FCEDIT
-is obsolete. Use
-.B HISTEDIT
-instead.
-.LI
-In the
-.B \-s
-option
-(to \fBfc\fR or \fBhist\fR command???)
-(
-and in obsolete versions, the editor name
-.B \-
-)
-is used to skip the editing phase and
-to re-execute the command.
-.LI
-The
-.B \-t
-option to \fBalias\fR builtin is is obsolete. It
-is used to set and list tracked aliases.
-There is no replacement.
-.LI
-The shell command line option
-.B \-t
-is obsolete. This option cause the shell to exit after reading
-and executing one command. The is no replacement (although ending
-\&"command" with the exit builtin should have the same effect).
-.LI
-As an obsolete feature of the "set" builtin,
-if the first
-.I arg\^
-is
-.B \-
-then the
-.B \-x
-and
-.B \-v
-options are turned off and the next
-.I arg
-is treated as the first argument.
-Using
-.B \+
-rather than
-.B \-
-causes these options to be turned off.
-These options can also be used upon invocation of the shell.
-.LE
-
diff --git a/usr/src/lib/libshell/common/README b/usr/src/lib/libshell/common/README
deleted file mode 100644
index 1feeec8a90..0000000000
--- a/usr/src/lib/libshell/common/README
+++ /dev/null
@@ -1,232 +0,0 @@
-This directory, and its subdirectories contain the source code
-for ksh-93; the language described in the second addition of
-the book, "The KornShell Command and Programming Language," by
-Morris Bolsky and David Korn which is published by Prentice Hall.
-ksh-93 has been compiled and run on several machines with several
-operating systems. The end of this file contains a partial list of
-operating systems and machines that ksh-93 has been known to run on.
-
-The layout of files for ksh-93 has changed somewhat since ksh-88,
-the last major release. Most of the source code for ksh remains in
-the sh directory. However, the shell editing and history routines
-are in the edit sub-directory. The code for shell built-ins is
-in the bltins directory. The data directory contains read-only
-data tables and messages that are used by the shell. The include
-files remain in the include directory and the shlib directory
-is gone. The features directory replaces the older install
-directory. The method for generating systems specific feature
-information has changed substantially.
-
-The Makefile file contains several compilation options that can be set
-before compiling ksh. Options are of the form SHOPT_option and become
-#define inside the code. These options are set to their recommended
-value and some of these may disappear as options in future releases.
-A value of 0, or no value represents off, 1 represents on.
-Note that == is needed, not =, because these are nmake state variables
-and changing their value will cause all modules that could be affected
-by this change to be recompiled.
-The options have the following defaults and meanings:
- ACCT off Shell accounting.
- ACCTFILE off Enable per user accounting info.
- AUDIT off For auditing specific users
- AUDITFILE "/etc/ksh_audit"
- APPEND on Allows var+=val string and array append.
- BASH off Bash compatibility mode. It is not fully implemented
- and is experimental.
- BRACEPAT on C-shell type abc{d,e}f style file generation
- CMDLIB_BLTIN off Makes all commands in libcmd.a builtins. The
- SH_CMDLIB_DIR nmake state variable can be used to
- specify a directory.
- CMDLIB_DIR off Sets CMDLIB_BLTIN=1 and provides a default value
- of "/opt/ast/bin" for SH_CMDLIB_DIR.
- COMPOUND_ARRAY
- on Allows all components of compound variables except the
- first to be any string by enclosing in [...]. It also
- allows components other than the last to be arrays.
- This is experimental and only partially complete.
- CRNL off <cr><nl> treated as <nl> in shell grammar.
- DYNAMIC on Dynamic loading of builtins. (Requires dlopen() interface.)
- ECHOPRINT off Make echo equivalent to print.
- ESH on Compile with emacs command line editing. The original
- emacs line editor code was provided by Mike Veach at IH.
- FILESCAN on Experimental option that allows fast reading of files
- using while < file;do ...; done and allowing fields in
- each line to be accessed as positional parameters.
- FS_3D off For use with 3-D file system. Enabled automatically for
- sytems with dynamic linking.
- KIA off Allow generation of shell cross reference database with -I.
- MULTIBYTE on Multibyte character handling. Requires mblen() and
- mbctowc().
- NAMESPACE on Allows namespaces. This is experimental, incomplete
- and undocumented.
- OLDTERMIO off Use either termios or termio at runtime.
- OO on Experimental object oriented extension. This option
- should disappear soon.
- OPTIMIZE on Optimize loop invariants for with for and while loops.
- P_SUID off If set, all real uids, greater than or equal to this
- value will require the -p flag to run suid/sgid scripts.
- PFSH off Compile with support for profile shell.
- RAWONLY off Turn on if the vi line mode doesn't work right unless
- you do a set -o viraw.
- SEVENBIT off Strip the eigth bit from characters.
- SPAWN off Use spawn as combined fork/exec. May improve speed on
- some systems.
- STATS on Add .sh.stats compound variable.
- SUID_EXEC on Execute /etc/suid_exec for setuid, setgid script.
- TIMEOUT off Set this to the number of seconds for timing out and
- exiting the shell when you don't enter a command. If
- non-zero, TMOUT can not be set larger than this value.
- TYPEDEF on Enable typeset type definitions.
- VSH on Compile with vi command line editing. The original vi
- line editor code was provided by Pat Sullivan at CB.
-
-The following compile options are set automatically by the feature testing:
- DEVFD Set when /dev/fd is a directory that names open files.
- SHELLMAGIC
- Set on systems that recognize script beginning with #! specially.
- VPIX Set on systems the have /usr/bin/vpix program for running MS-DOS.
-
-
-In most instances, you will generate ksh from a higher level directory
-which also generates libcmd and libast libraries on which ksh depends.
-However, it is possible to generate ksh, with by running make -f ksh.mk
-in this directory. The ksh.mk file was generated from the nmake Makefile.
-If you do not have make or nmake, but do have a Version 7 UNIX compatible
-shell, then you can run the script mamexec < Mamfile to build ksh.
-If you have nmake, version 2.3 or later, you can use it without the -f ksh.mk.
-In either case, ksh relies on libraries libast and libcmd which must be
-built first. The binary for ksh becomes the file named ./ksh which can
-be copied to where ever you install it.
-
-If you use old make or the Mamfile, and you system has dynamic shared
-libraries, then you should define the variables mam_cc_static and
-mam_cc_dynanamic as the compiler options that request static linking
-and dynamic linking respectively. This will decrease the number of
-shared libraries that ksh need and cut startup time substantially.
-
-The makefile should also generate shcomp, a program that will precompile
-a script. ksh93 is able to recognize files in this format and process
-them as scripts. You can use shcomp to send out scripts when you
-don't want to give away the original script source.
-
-It is advisable that you put the line PWD=$HOME;export PWD into the
-/etc/profile file to reduce initialization time for ksh.
-
-To be able to run setuid/setgid shell scripts, or scripts without read
-permission, the SUID_EXEC compile option must be on, and ksh must be installed
-in the /bin directory, the /usr/bin directory, the /usr/lbin directory,
-or the /usr/local/bin directory and the name must end in sh. The program
-suid_exec must be installed in the /etc directory, must be owned by root,
-and must be a suid program. If you must install ksh in some other directory
-and want to be able to run setuid/setgid and execute only scripts, then
-you will have to change the source code file sh/suid_exec.c explicitly.
-If you do not have ksh in one of these secure locations, /bin/sh will
-be invoked with the -p options and will fail when you execute a setuid/setgid
-and/or execute only script. Note, that ksh does not read the .profile
-or $ENV file when it the real and effective user/group id's are not
-equal.
-
-The tests sub-directory contains a number of regression tests for ksh.
-To run all these tests with the shell you just built, go to the tests
-directory and run the command
- SHELL=$dir/ksh $dir/ksh shtests
-where dir is the directory of the ksh you want to test.
-
-The file PROMO.mm is an advertisement that extolls the virtues of ksh.
-The file sh.1 contains the troff (man) description of this Shell.
-The file nval.3 contains the troff (man) description of the name-value
-pair library that is needed for writing built-ins that need to
-access shell variables.
-
-The file sh.memo contains a draft troff (mm) memo describing ksh. The
-file RELEASE88 contains the changes made for ksh88. The file RELEASE93
-contains the changes made in this release since ksh-88. The file
-RELEASE contains bug fixes made in this release since ksh-88. The file
-COMPATIBILITY contains a list of incompatibilities with ksh-88. The
-file bltins.mm is a draft troff (mm) memo describing how to write
-built-in commands that can be loaded at run time.
-
-Most of the work for internationalization has been done with ksh93.
-The file ksh.msg is a generated file that contains error messages
-that need to be translated. In addition, the function translate()
-in sh/init.c has to be completed to interface with the dictionary
-lookup. The translate function takes two argument, the string
-that is to be translated and a type which is
- 0 when a library string needs translation.
- 1 when one of the error messages in ksh.msg needs translation.
- 2 when a string in a script needs translation. You use a $ in front
- of a double quoted string in a script to indicate that it
- needs translation. The -D option for ksh builds the dictionary.
-The translate routine needs to return the translated message.
-For dictionaries that need to use a numeric key, it should be
-possible to use the strhash() function to generate numbers to
-go along with each of the messages and to use this number both
-when generating the dictionary and when converting strings.
-If you encounter error messages of type 1 that are not be translated via
-this translate() function send mail to the address below.
-
-Please report any problems or suggestions to:
-
-dgk@research.att.com
-
-
-ksh93 has been compiled and alpha tested on the following. An asterisk
-signifies that ksh has been installed as /bin/sh on this machine.
-
-* Sun OS 4.1.[123] on sparc.
- Sun OS 4.1.1 on sun.
- Solaris 2.[1-9] on sparc.
- Solaris 2.[4-8] on X86.
- HP/UX 8 on HP-9000/730.
- HP/UX 9 on HP-9000/730.
- HP/UX 10 on HP-9000/857.
- HP/UX 11 on pa-risc.
- System V Release 3 on Counterpoint C19
- System V Release 4 on AT&T Intel 486.
- System V Release 4 on NCR 4850 Intel 486.
- IRIX Release 4.0.? System V on SGI-MIPS.
- IRIX Release 5.1 System V on SGI-MIPS.
- IRIX Release 6.[1-5] System V on SGI-MIPS.
- System V Release 3.2 on 3B2.
- UTS 5.2.6 on Amdahl 3090,5990,580.
- System V Release 3.2 on i386.
- SMP_DC.OSx olivetti dcosx MIServer-S 2/128.
- SMP_DC.OSx Pyramid dcosx MIServer-S 2/160 r3000.
- 4.3BSD on Vax 8650.
- AIX release 2 on RS6000.
- AIX 3.2 on RS6000.
- Linux 1.X on Intel
- Linux 2.X on Intel
- Linux 2.X on Alpha
- Linux 2.X on Alpha
- Linux 2.X on OS/390
- Linux 2.X on sparc
- Linux 2.4 on intel itanium 64
- Linux Slackware on sparc64
-* Linux ARM on i-PAQ
- OSF1 on DEC alpha.
- OSF4 on DEC alpha.
- UMIPS 4.52 on mips.
- BSD-i [2-4] on X86.
- OpenBSD on X86
- NetBSD on X86
- FreeBSD on X86
- NeXT on Intel X86.
- NeXT on HP.
-* Windows NT using UWIN on X86
-* Windows NT using UWIN on alpha
- Windows NT using Cygwin on X86
- Windows NT with NutCracker libraries.
- Windows NT with Portage libraries.
- Windows 3.1 using custom C library.
- OpenEdition on MVS
- Darwin OS X on PPC
- MVS on OS 390
- SCO Openserver 3.2 on X86
- Unixware 7 on X86
-
-Good luck!!
-
-David Korn
-dgk@research.att.com
-
diff --git a/usr/src/lib/libshell/common/RELEASE b/usr/src/lib/libshell/common/RELEASE
deleted file mode 100644
index b8fc92511a..0000000000
--- a/usr/src/lib/libshell/common/RELEASE
+++ /dev/null
@@ -1,2204 +0,0 @@
-10-03-05 --- Release ksh93t+ ---
-10-03-05 A varibale unset memory leak has been fixed and tests/leaks.sh
- has been added to verify the fix.
-10-03-04 Documentation, comment, and disgnostic spelling typos corrected.
-10-02-14 Fix sh_getenv() initialization to cooperate with the 3d fs.
-10-02-12 A bug in which the get discipline function was not invoked for
- associative array subscripts for unset array elements has been fixed.
-10-02-12 A bug which could occur if the last line of a script was an eval
- that executed multiple commands has been fixed.
-10-02-02 A buffer overflow in read and another in binary type base64
- encoding were fixed.
-10-01-20 A bug in the evaluation of arithmetic expression in which the
- subscript was evaluated twice for $((foo[x++]++)) has been fixed.
-10-01-19 A workaround for a double-free of a trap in both a subshell and its
- parent has been added.
-10-01-18 A bug in type handling of typeset -H has been fixed.
-10-01-15 The "adding empty subscript" warning now only emitted with -x set.
-10-01-01 A bug in the parser in which '$((case i in i):;esac);:))' was not
- parsed correctly was fixed.
-10-01-01 A bug in the parser in which '$(( 2 , 3.6 ))' dumped core for locales
- with radix char , and thousands separator . has been fixed.
-09-12-28 A bug in the handling of SIGCLD on systems that generated SIGCLD
- while blocked waiting for process to complete has been fixed.
-09-12-24 ast setlocale() reworked to differentiate env var changes from user
- override.
-09-12-18 A bug with the SHOPT_BGX option set which disabled traps for signals
- < SIGCHLD when a trap for a signal > SIGCHLD was set has been fixed.
-09-12-18 A bug where [[ -v var ]] was incorrect for some variables (including
- LC_* vars) has been fixed.
-09-12-15 A bug that produced a syntax error when a multibyte character
- straddled a buffer boundary has been fixed.
-09-12-11 A bug where the subscript of an unset variable was not evaluated has
- been fixed.
-09-12-09 A bug where shcomp dumped core on certain syntax errors has been fixed.
-09-12-07 A bug where a parent shell environment var reset in a subshell removed
- the value in subsequent children of the parent shell has been fixed.
-09-12-04 A bug in which in some cases a trap in a function executed in
- a subshell could trigger twice has been fixed.
-09-12-03 A bug in which SHLVL exported with some attributes could cause
- the shell to abort at startup has been fixed.
-09-12-02 A bug with pipefail in which the shell could hang waiting for the
- writer to complete before the last reader command has been fixed.
-09-11-30 A bug in which a trap could be inherited by the first element of
- a pipeline when the command had more than 63 arguments that did
- not contain any macro expansions has been fixed.
-09-11-19 When read from a terminal was called from with a while or foo loop,
- and an edit mode was on, a backspace or erase no longer will
- overwrite the prompt.
-09-11-17 Change .paths parse to handle BUILTIN_LIB=foo BUILTIN_LIB=foo-1.2.
-09-11-17 Inside a function, typeset foo.bar will bind foo to global variable
- foo if local variable foo does not exist, instead of creating a
- local variable.
-09-11-17 "read -n1" from the terminal has been fixed to read exactly one character.
-09-11-11 Job control now works for subshell commands, (...).
-09-11-11 If set -e is on for an interactive shell errors in special builtins
- now cause the shell to exit.
-09-11-11 A bug in which an interrupt handler processed during the read builtin
- when IFS did not contain a new line has been fixed.
-09-11-09 A bug in which a variable that has been unset in a subshell and then
- exported from that subshell does not show up in the environment
- has been fixed.
-09-11-02 ``,2'' is now a valid numeric constant for locales with
- decimal_point=','.
-09-11-02 A bug where "return" in .profile did not restore the shell state
- has been fixed.
-09-10-31 A bug that corrupted saved exit status when pids wrapped around has
- been fixed.
-09-10-26 A bug in { LANG LC_ALL LC_category } ordering has been fixed in -last.
-09-10-16 A bug where notification to libast that the environment has changed
- has been fixed.
-09-10-12 A bug in which a function loaded in a subshell could leave side
- effects in the parent shell has been fixed.
-09-10-12 A bug in converting a printf %d operand to a number when the operand
- contains multiple subscripts for the same variable has been fixed.
-09-10-09 A bug in the handling of the escape character \ in directory prefixes
- in command completion has been fixed.
-09-10-09 $PATH processing has been changed to delay dir stat() and .paths
- lookup until the directory is needed in the path search.
-09-09-28 Call the ast setlocale() intercept on unset too.
-09-09-24 A bug in which LANG=foo; LC_ALL=foo; unset LC_ALL; did not revert
- LC_CTYPE etc. to the LANG value has been fixed.
-09-09-17 A bug in which unsetting SVLVL could cause a script invoked by
- name without #! to core dump has been fixed.
-09-09-16 A bug in which a pipeline in a here-document could hang when the
- pipefail option was on has been fixed.
-09-09-09 A bug in the processing of line joining in here documents which
- occurred when a buffer began with <escape><new-line> has been fixed.
-09-09-09 A leading ; with commands in a brace group or parenthesis group
- no longer causes an error. It now is used for the "showme" option.
-09-09-09 A bug in which a subshell containing a background process could
- block until the background process completed has been fixed.
-09-09-04 A bug in handing ${var[sub]}, where var is a nameref has been fixed.
-09-09-03 A bug which caused an index array to have the wrong number of elements
- when it was converted from a compound variable by adding an another
- element has been fixed.
-09-09-03 Specifying export for a compound variable now generates an error.
-09-09-02 $"..." localizations strings are no longer recognized inside `...`.
-09-09-01 A bug in the for loop optimizer in the handling of type static
- variables has been fixed.
-09-09-01 An error message is not displayed when * and @ are used as subscripts.
-09-09-01 Several bugs in the processing for types that included an associative
- array of another type has been fixed.
-09-09-01 A bug in the tracing of [[ a < b ]] and [[ a > b ]] has been fixed.
-09-08-26 The .sh.file variable was not being set for a script that was run
- by name and didn't start with #! and this has been fixed.
-09-08-25 A bug in which a function called to deeply from command substitution
- did not display an error message has been fixed.
-09-08-24 When processing profiles, ksh93 now violates the POSIX standard and
- treats &> as a redirection operator similar to bash.
-09-08-23 A bug in the handling of the trap on SIGPIPE that could lead to a
- memory fault has been fixed.
-09-08-21 A bug in the handling of the comma operator in arithmetic expressions
- that could cause a core dump on some systems has been fixed.
-09-08-20 A bug in which a compound variable containing an array of a type
- that doesn't have any elements now expands correctly.
-09-08-19 A bug which disabled function tracing inside a function after
- a call to another function has been fixed.
-09-08-19 A bug in which initializing a compound variable instance to another
- compound variable by name has been fixed.
-09-08-18 A bug in which compound variable instances could be lost after
- an instance that invoked a type method discipline has been fixed.
-09-08-18 A bug in which a discipline function for a type applied to an
- array instance when invoked in a function ignored the subscript
- has been fixed.
-09-08-18 A scoping error with variables in arithmetic expression with
- type variables when reference with a name reference has been fixed.
-09-08-10 Several memory leaks were fixed primarily related to subshells.
-09-08-06 A bug in which setting the trap on CHLD to ignore could cause
- a script to hang has been fixed.
-09-07-08 A bug in the processing of name reference assignments when it
- contained pattern expansions with quoting has been fixed.
-09-06-22 The default width for typeset -X has been changed so that there
- should be no loss of precision when converting to a string.
-09-06-19 A bug in the printing of array elements for binary variables with
- printf %B has been fixed.
-09-06-19 A bug which caused a core dump with trap DEBUG set with an array
- assignment with no elements has been fixed.
-09-06-19 A bug with read with typeset -b -Z<num> has been fixed.
-09-06-19 Two bugs related to read -b for array variables has been fixed.
-09-06-19 A bug with typeset for compound variables containing arrays of
- compound variables has been fixed.
-09-06-18 A bug in appending a compound variable to a an indexed array of
- compound variables has been fixed.
-09-06-18 A bug which occurs when appending a compound variable to an indexed
- array element has been fixed.
-09-06-18 Setting VISUAL to a value other than one ending in vi or emacs will
- no longer unset the edit mode.
-09-06-17 A bug in typeset -m when moving a local compound variable to a
- global compound variable via a name reference has been fixed.
-09-06-17 A bug in appending to nodes of an array of compound variables when
- addressing them via nameref has been fixed.
-09-06-17 A bug in typeset -p var, when var is an array of compound variables
- in which the output only contained on array element has been fixed.
-09-06-17 The prefix expansion ${!y.@} now works when y is a name
- reference to an element of an array.
-09-06-16 Traps on signals that are ignored when the shell is invoked
- no longer display. Previously they were ignored as required but
- would be listed with trap -p.
-09-06-12 A bug in vi edit mode in which hitting the up arrow key at the
- end of a line longer than 40 characters which caused a core dump
- has been fixed.
-09-06-11 A bug in which "eval non-builtin &" would create two processes,
- one for the & and another for non-builtin has been fixed.
-09-06-08 When var is an identifier and is unset, ${var} no longer tries to
- run command substitution on the command var.
-09-06-08 Process substitution arguments of the form <(command) can now be
- used following the < redirection operator to redirect from command.
-09-05-13 A bug in which redirections of the form 2>&1 1>&5 inside command
- substitution could cause the command substitution to hang has been
- fixed.
-09-05-12 To conform with POSIX, the -u option only checks for unset variables
- and subscript elements rather than checking for all parameters.
-09-05-12 A bug which could cause a core dump when a variable whose name
- begins with a . was referenced as part of a name reference inside
- a function has been fixed.
-09-05-01 A bug that caused a core dump when SIGWINCH was received and
- both vi and emacs mode were off has been fixed.
-09-04-22 Default alias compound='typeset -C' added.
-09-04-15 A bug that caused ${...;} to hang for large files has been fixed.
-09-04-08 A change was made in the -n option which printed out an incorrect
- warning with <>.
-09-04-07 The emacs edit command M-_ and M_. and the vi command _ was fixed
- to handle the case there there is no history file.
-09-04-05 A bug in handling new-lines with read -n has been fixed.
-09-04-05 The ENV variable defaults the the file named by $HOME/.kshrc rather
- then to the string $HOME/.kshrc.
-09-03-31 A bug in which a nested command substitution with redirections could
- leave a file descriptor open has been fixed.
-09-03-24 ksh now only uses the value of the _ variable on startup if it can
- verify that it was set by the invoking process rather than being
- inherited by some other ancestor.
-09-03-24 When ksh is invoked without -p and ruid!=euid, and the shell is
- compiled without SHOPT_P_UID or ruid<SHOPT_P_UID, the shell now
- enables the -p option. The previous version instead set the
- euid to the ruid as it does for set +p.
-09-03-24 When SHOPT_P_UID is defined at compile time and the shell is started
- without -p and ruid!=euid and ruid>=SHOPT_P_UID then euid is set
- to ruid. A bug that did the wrong test (ruid<SHOPT_P_UID) was fixed.
-09-03-17 The sleep(1) builtin now accept and ISO 8601 PnYnMnDTnHnMnS
- duration or date(1) compatible date/time operand.
-09-03-10 If a variable that was left or right justified or zero-filled was
- changed with a typeset statement that was left or right justified
- or zero-filled, then the original justification no longer affects
- the result.
-09-03-10 A bug in the handling of traps when the last command in a script
- is a subshell grouping command has been fixed.
-09-03-03 A bug in which an expansion of the form ${!prefix@} could generate
- an exception after the return from a function has been fixed.
-09-02-02 A bug in restricted mode in which the value of ENV could be
- changed from within a function has been fixed.
-09-02-02 A bug in which an erroneous message indicating that a process
- terminated with a coredump has been fixed.
-09-02-02 The exit status when exit was called without an argument from
- a signal handler was incorrect and has been fixed.
-09-02-02 A bug in which a function autoloaded in a subshell could cause
- a core dump when the subshell completed has been fixed.
-09-02-02 A bug in which 2>&1 inside a command substitution wasn't working
- correctly has been fixed.
-09-02-02 A bug in the call stack of arithmetic function with 2 args
- returning int has been fixed.
-09-01-30 A bug in which 'eval print \$0' inside a function was giving the
- wrong value for $0 has been fixed.
-09-01-28 A bug in which a command substitution could return an exit status
- of 127 when the pipefail option is enabled has been fixed.
-09-01-26 ksh93 now generates an error message if you attempt to create
- a global name reference to a local variable.
-09-01-26 The [[ -v var ]] operator was modified to test for array elements.
-09-01-23 The redirection operator <>; was added. It is similar to <>
- except that if the command it is applied to succeeds, the file
- is truncated to the offset at the command completion.
-09-01-23 The default file descriptor for <> was changed to 1.
-09-01-20 A bug in which the exit status specified in an exit trap was
- not used when a process terminated with a signal has been fixed.
-09-01-19 A bug in which a signal whose default action is to terminate
- a process could be ignored when the process is running a sub-shell
- has been fixed.
-09-01-19 A bug in which sending SIGWINCH to a process that reads from a pipe
- could cause a memory fault has been fixed.
-09-01-16 The -R unary operator was added to [[...]] and test to check whether
- a variable is a name reference.
-09-01-16 The -v unary operator was added to [[...]] and test to check whether
- a variable is set.
-09-01-14 The unset built-in was modified to return 0 exit status when
- unsetting a variable that was unset to conform with the POSIX
- standard.
-09-01-14 The unset built-in was modified to continue to unset variables
- after encountering a variable that it could not unset to
- conform to the POSIX standard.
-09-01-14 The parameter expansion ${x+value} no longer expands the value of
- the variable x when determining whether x is set or not.
-09-01-13 A bug in which background jobs and pipelines that were not waited
- for could, in rare instances, cause the shell to go into an infinite
- loop or fail has been fixed.
-09-01-06 A bug in indexed arrays of compound variables in which referencing
- non-existent sub-variable in an arithmetic expression could cause
- the sub-variable to be created has been fixed.
-09-01-05 A bug in which the \ character did not escape extended regular
- expression pattern characters has been fixed.
-08-12-24 A bug in which killing the last element of a pipe did not cause
- a write to the pipe to generate a SIGPIPE has been fixed.
-08-12-19 A bug which could cause command substitution to hang when the
- last element of a pipeline in a command substitution was a built-in
- and the output was more that PIPE_BUFF.
-08-12-18 A bug which occurs when a here documented marker embedded in a
- command substitution occurs on a buffer boundary has been fixed.
-08-12-17 A bug in the output of typeset -p for variables that had attributes
- but did not have a value has been fixed.
-08-12-16 A bug in which a name reference to a name reference variable that
- references an array element has been fixed.
-08-12-16 A bug in which a variable given both the -A and -C attribute along
- with an initial assignment didn't work correctly has been fixed.
-08-12-10 The [[ -t fd ]] test was fixed to handle fd>9.
-08-12-10 A bug where function stack misalignment could cause a bus error
- has been fixed.
-08-12-09 Command completion was changed to use \ to quote special characters
- instead of quoting the argument in single quotes.
-08-12-07 A bug in typeset -m which occurred when the target node was an
- associative array element has been fixed.
-08-12-07 A timing bug on some systems (for example darwin), that could
- cause the last process of a pipeline entered interactively to fail
- with an "Exec format error" has been fixed.
-08-12-04 SHOPT_BGX enables background job extensions. Noted by "J" in
- the version string when enabled. (1) JOBMAX=n limits the number
- of concurrent & jobs to n; the n+1 & job will block until a
- running background job completes. (2) SIGCHLD traps are queued
- so that each completing background job gets its own trap; $! is
- set to the job pid and $? is set to the job exit status at the
- beginning of the trap. (3) sleep -s added to sleep until the time
- expires or until a signal is delivered.
-08-12-04 The sign of floating point zero is preserved across arithmetic
- function calls.
-08-12-04 A bug that caused print(1) to produce garbled stdout/stderr
- output has been fixed.
-08-12-04 A bug in which printf "%d\n" "'<euro>'" did not output the
- numerical value of the EURO symbol, 8354, has been fixed.
-08-11-24 /dev/fd* and /dev/std* redirections are first attempted with
- open() to preserve seek semantics; failing that the corresponding
- file descriptors are dup()'d.
-08-11-20 A bug which could cause a core dump if a function compiled with
- shcomp was found has been fixed.
-08-11-20 A bug in which jobs were not cleared from the jobs table for
- interactive shells when the pipefail option is on has been fixed.
-08-11-11 A bug in which a field that was unset in a type definition and later
- set for an instance could appear twice when displaying the variable
- has been fixed.
-08-11-11 A bug in which running a simple command & inside a function would
- not return the correct process id has been fixed.
-08=11-10 A bug in which the exit status of a command could be lost if the pid
- was that of the most recent command substitution that had completed
- has been fixed.
-08-11-10 The maximum depth for subshells has been increased from 256 to 65536.
-08-11-06 A bug which could cause a core dump when the _ reference variable was
- used as an embedded type with a compound assignment has been fixed.
-
-08-10-31 --- Release ksh93t ---
-08-10-31 Variable scoping/initialization bugs that could dump core were fixed.
-08-10-24 The lexer now accepts all RE characters for patterns prefixed
- with a ksh ~(...) option expression.
-08-10-24 For ${var/pat/sub} \0 in sub expands to the text matched by pat.
-08-10-18 A bug in array scoping that could dump core has been fixed.
-08-10-10 read -n and -N fixed to count characters in multibyte locales.
-08-10-10 A bug that mishandled _.array[] type references has been fixed.
-08-10-09 ${.sh.version} now contains a concatenation of the following (after
- 'Version') denoting compile time features:
- A SHOPT_AUDIT
- B SHOPT_BASH
- L SHOPT_ACCT
- M SHOPT_MULTIBYTE
-08-10-09 A bug that caused subshell command substitution with redirection
- to hang has been fixed.
-08-10-08 Output errors, other than to stderr, now result in a diagnostic.
-08-10-08 ksh93 now supports types that contain arrays of other types as
- members. Earlier versions core dumped in this case.
-08-10-05 A bug which caused the shell to emit a syntax error for an arithmetic
- statement of the form (( var.name[sub] = value)) has been fixed.
-08-10-01 A bug that caused subshell command substitution to hang has
- been fixed.
-08-09-29 When the -p export option of typeset is used with other options,
- only those variables matching the specified options are displayed.
-08-09-29 When the shell reads the environment and finds variables that are
- not valid shell assignments, it now passes these on to subsequent
- commands rather than deleting them.
-08-09-29 A bug in the display of compound variables containing an indexed
- array of compound variables has been fixed.
-08-09-29 A bug in the display of compound variables containing an associative
- array with a subscript containing a . in the name has been fixed.
-08-09-26 A core dump in the subshell environment restore has been fixed.
-08-09-24 $(...) has been fixed to properly set the exit status in $?.
-08-09-23 $(<...) with IFS=$'\n\n' has been fixed to retain all but the last
- of multiple trailing newlines.
-08-09-23 The -p option to typeset when used with other attributes, restricts
- the output to variables with the specified attributes.
-08-09-22 A bug that sometimes lost the exit status of a job has been fixed.
-08-09-21 A bug that retained trailing command substitution newlines in
- cases where the command caused the shell to fork has been fixed.
-08-09-19 type, whence -v, and command -v were fixed to comply with POSIX
- by writing 'not found' diagnostics to the standard error.
-08-09-18 test and [...] were fixed to comply with POSIX in the case
- of test '(' binop ')' where binop is a valid binary test operator.
-08-09-16 If a method discipline named create is specified when defining a
- type, this function will be called when an instance is created.
-08-09-15 The variable _ is now set as a reference to the compound variable
- when defining a compound variable or a type.
-08-09-10 The shell now prints an error message when the type name specified
- for an indexed array subscript is not an enumeration type.
-08-09-10 A bug in which a subshell that spawned a background process could
- loose output that was produced after the foreground completed
- has been fixed.
-08-09-10 A timing bug on some systems that could cause coprocesses started by a
- subshell to not clean up and prevent other coprocesses has been fixed.
-08-09-09 The typeset -m option is now able to rename array elements from
- the same array.
-08-09-09 The exit status of 2 from the DEBUG trap causes the next command
- to be skipped. An exit value of 255 from a DEBUG trap called from
- a function causes the function to return.
-08-09-08 A bug in which a coprocess created in a subshell that did not
- complete when the subshell terminated could prevent a coprocess
- from being created in the parent shell has been fixed.
-08-09-05 An assignment of the form name1=name2 where name1 and name2
- are both compound variables causes name1 to get a copy of name2.
- name1+=name2 causes name2 sub-variables to be appended to name1.
-08-09-05 A bug in which unsetting a compound variable did not unset all
- the sub-variables has been fixed.
-08-09-01 A bug in the subshell cleanup code that could cause SIGSEGV has
- been fixed.
-06-08-26 The SHLVL variable which is an environment variable used by bash
- and zsh that gets incremented when the shell starts.
-08-08-25 For an indexed array, a negative subscript now refers to offsets
- from the end so that -1 refers to the last element.
-08-08-24 An alignment error for shorts on 64 bit architectures has been fixed.
-08-08-22 If oldvar is a compound variable, typeset -C newvar=oldvar creates
- newvar as a copy of oldvar.
-08-08-19 The ALRM signal no longer cause the sleep builtin to terminate.
-08-08-13 When used in an arithmetic expression, the .sh.version variable
- now produces a number that will be increasing for each release.
-08-08-11 A bug in which type instantiation with a compound assignment in
- a dot script in which the type is defined has been fixed.
-08-08-07 The -m option has been added to typeset to move or rename a
- variable. Not documented yet.
-08-08-06 A bug in read when used in a loop when a prompt was specified
- when reading from a terminal has been fixed.
-08-08-01 A bug with the pipefail option in which a nested pipeline could
- cause an asynchronous command to block has been fixed.
-08-08-01 A for loop optimizer bug that treats .sh.lineno as an invariant
- has been fixed.
-08-07-30 A bug in which expanding compound variable that had a get discipline
- from with a here document could cause a syntax error has been fixed.
-08-07-18 A bug in which a nameref caused a local variable to be created
- rather than binding to an existing variable in the global scope
- has been fixed.
-08-07-17 A bug which occurred when a nameref was created from within a
- function that was part of a pipeline has been fixed.
-08-07-14 The compile option SHOPT_STATS was added. With this option the
- compound variable .sh.stats keeps usage statistics that could help
- with performance tuning.
-08-07-10 The output of set now always uses a single line for each variable.
- For array variables, the complete set of values is now displayed.
-08-07-09 The typeset -C option can be used with arrays to indicate that
- each element should default to a compound variable.
-08-07-08 The %B format now outputs compound variables and arrays. The
- alternate flag # can be used to cause output into a single line.
-08-07-03 When the window change signal, WINCH, is received, the current
- edit line is redrawn in place.
-08-07-01 A bug in the handling of shared variables when inside an embedded
- type has been fixed.
-08-06-29 A bug in multiline edit mode which occurred when the prompt length
- was three characters or less has been fixed.
-08-06-23 A bug in which the SIGCLD was not be triggered when background
- jobs completed has been fixed.
-08-06-23 KSH_VERSION added as a name reference to .sh.version.
-08-06-20 type now outputs 'special builtin' for special builtins.
-08-06-19 A couple of bugs in multi-dimensional arrays have been fixed.
-08-06-19 A bug in which a syntax error in a dot script could generated
- a syntax error in the next subsequent command has been fixed.
-08-06-17 Reduced the maximum function call depth to 2048 to avoid exceptions
- on some architectures.
-08-06-16 A bug in which printf "%B" could generate an exception when the
- specified variable was not set has been fixed.
-08-06-16 When typeset -p is followed by variable names, it now displays
- the attributes names and values for the specific names.
-08-06-14 A bug that could effect the drawing of the screen from multiline
- emacs or gmacs mode when walking up the history file has been fixed.
-08-06-13 A bug in which a compound variable defined in a subshell could
- have side effects into the parent shell has been fixed.
-08-06-13 A number of bugs related to using .sh.level to set the stack from
- for DEBUG traps have been fixed.
-08-06-13 The .sh.lineno variable has been added. When .sh.level is changed
- inside a DEBUG trap, the .sh.lineno contains the calling line number
- for the specified stack frame.
-08-06-13 The .sh.level variable has been documented and now works.
-08-06-11 The -C option has been added to read for reading compound command
- definitions from a file.
-08-06-11 The . command is now permitted inside a compound command definition.
- The dot script can contain declaration commands and dot commands.
-08-06-09 Add -C option to typeset so that typeset -C foo, is equivalent
- to foo=().
-08-06-09 Added -n warning message for typeset option orderings that are valid
- with ksh88 but not valid with ksh93, for example Lx5.
-08-06-09 A bug in which the return value for an assignment command containing
- a command substitution with that failed was zero when the assignment
- contained redirections has been fixed.
-08-06-09 A bug in the quoting of $ inside a ERE pattern ~(E)(pattern)
- has been fixed.
-08-06-06 A bug when processing `` command substitution with the character
- sequence \$' has been fixed.
-08-06-02 When defining a type, the typeset -r attribute causes this field
- to be required to be specified for each instance of the type and
- does not allow a default value.
-08-06-02 Several bugs in which compound variables were modified by
- subshells have been fixed.
-08-05-22 The ceil function has been added to the math functions.
-08-05-21 A bug in which a name reference defined in a function and passed
- as an argument to another function could cause an incorrect binding.
-08-05-21 A bug in freeing compound variables that are local to functions
- has been fixed.
-08-05-19 The array expansions ${array[sub1..sub2]} and ${!array[sub1..sub2]}
- to expand to the value (or subscripts) for array between sub1 and
- sub2 inclusive. For associative arrays, the range is based on
- location in the POSIX locale. The .. must be explicit and cannot
- result from an expansion.
-08-05-15 The trap on SIGCLD is no longer triggered by the completion of
- the foreground job as with ksh88.
-08-05-14 A bug in the implementation of the editing feature added on
- 07-09-19 in emacs mode has been fixed.
-08-05-12 A bug in processing the test built-in with parenthesis has been
- fixed.
-08-05-12 The unset built-in now returns non-zero when deleting an array
- subscript that is not set.
-08-05-08 Changing the value of HISTFILE or HISTSIZE will cause the old
- history file to be close and reopened with the new name or size.
-08-05-08 When FPATH is changed functions that were found via a path search
- will be searched for again.
-08-05-08 A parser bug in which reserved words and labels were recognized
- inside compound indexed array assignment after a new-line has
- been fixed.
-08-05-07 A bug in getopts when handling numerical option arguments has
- been fixed.
-08-05-07 The typeset -S option was added for variables outside type
- definitions to provide a storage class similar to C static
- inside a function defined with function name. When outside
- type definitions and outside a function, the -S option cause
- the specified variable so be unset before the assignment and
- before the remaining attributes are supplied.
-08-05-07 A bug that affected the cursor movement in multiline mode when
- a character was deleted from near the beginning of the any
- line other than the first.
-08-05-01 In multiline edit mode, the refresh operation will now clear
- the remaining portion of the last line.
-08-05-01 A bug in computing prompt widths for the edit modes for prompts
- with multibyte characters has been fixed.
-08-05-01 A bug in the multiline edit mode which could cause the current
- line to be displayed incorrectly when moving backwards from third
- or higher line to the previous line has been fixed.
-08-05-01 A bug in which options set in functions declared with the function
- name syntax were carried across into functions invoked by these
- functions has been fixed.
-08-04-30 A bug which could cause a coprocess to hang when the read end
- is a builtin command has been fixed.
-08-04-30 The emacs and vi editors have been modified to handle window
- change commands as soon as they happen rather than waiting for
- the next command.
-08-04-28 A bug in which ${!x} did not expand to x when x was unset has been
- fixed.
-08-04-27 A bug in which the assignment x=(typeset -a foo=([0]=abc)) created
- x.foo as an associative array has been fixed.
-08-04-25 A bug in which $# did not report correctly when there were more
- than 32K positional parameters has been fixed.
-08-04-04 Choose the name _ as the sub-variable that holds type or instance
- specific data used by discipline functions.
-08-03-27 A bug in which the terminal group was not given back to the parent
- shell when the last part of a pipeline was handled by the parent shell
- and the other parts of the pipeline complete has been fixed.
- The symptom was that the pipeline became uninterruptable.
-08-03-25 A bug in restricted mode introduced in ksh93s that caused scripts
- that did not use #! to executed in restricted mode has been fixed.
-08-03-25 A bug in which the pipefail option did not work for a pipeline
- within a pipeline has been fixed.
-08-03-24 A bug in which OPTIND was not set correctly in subshells has
- been fixed.
-08-03-24 A bug which could cause a memory exception when a compound variable
- containing an indexed array with only element 0 defined was expanded.
-08-03-20 A bug in which ${!var[sub].*} was treated as an error has been fixed.
-08-03-20 Associative array assignments of the form ([name]=value ...)
- now allow ; as well as space tab and new line to separate elements.
-08-03-18 A buffering problem in which standard error was sometimes
- not flushed before sleep has been fixed.
-08-03-17 A bug in which a signal sent to $$ while in a subshell would be
- sent to the subshell rather than the parent has been fixed.
-08-03-17 --default option added to set(1) to handle set +o POSIX semantics.
- set --state added as a long name alias for set +o.
-08-03-14 A bug in which using monitor mode from within a script could
- cause the terminal group to change has been fixed.
-08-03-10 The new ${...} command substitution will treat the trailing }
- as a reserved word even if it is not at the beginning of a command,
- for example, ${ date }.
-08-03-10 If the name of the ENV begins with /./ or ././ then the
- /etc/ksh.kshrc file will not be executed on systems that support
- this interactive initialization file.
-08-03-07 A bug in which ksh -i did not run the ENV file has been fixed.
-08-03-07 A bug in which ulimit did not always produce the same output as
- ulimit -fS has been fixed.
-08-03-04 A bug in multiline mode in emacs and vi mode which could cause the
- cursor to be on the wrong line when interrupt was hit has been fixed.
-08-03-03 The change made in ksh93s+ on 07-06-18 in which braces became
- optional for ${a[i]} inside [[...]] was restored in the case
- where the argument can be a pattern.
-08-03-03 A bug in which creating a name reference to an associative array
- instance would fail when the subscript contained characters [ or
- ] has been fixed.
-08-02-29 The redirection operator >; has been added which for non-special
- files, generates the output in a temporary file and writes the
- specified file only of the command has completed successfully.
-08-02-15 A bug in ${var/pattern/string} for patterns of the form ?(*) and +(*)
- has bee fixed.
-08-02-07 A bug in which test \( ! -e \) produced an error has been fixed.
-08-02-14 The typeset -a option can now optionally be followed by the name
- of an enumeration type which allows subscripts to be enumerations.
-08-02-14 The enum builtin which creates enumeration types has been added.
-08-02-12 The backoff logic when there are no more processes has been fixed.
-08-02-07 The -X option has been added to typeset. The -X option creates
- a double precision number that gets displayed using the C99 %a
- format. It can be used along with -l for long double.
-08-01-31 The -T option to typeset has been added for creating typed
- variables. Also the -h and -S options have been added to
- typeset that are only applicable when defining a type.
-08-01-31 The prefix expansion operator @ has been added. ${@name}
- expands to the type of name or yields the attributes.
-07-11-15 A bug in the macro expander for multibyte characters in which
- part of the character contains a file pattern byte has been fixed.
-07-10-03 A bug in which : was not allowed as part of an alias name has been
- fixed.
-07-09-26 A bug in which appending a compound variable to a compound variable
- or to an index array didn't work has been fixed.
-07-09-19 In both emacs and vi edit mode, the escape sequence \E[A (usually
- cursor up, when the cursor is at the end of the line will fetch
- the most recent line starting with the current line.
-07-09-18 The value of ${!var} was correct when var was a reference to an
- array instance.
-07-09-18 The value of ${!var[sub]} was not expanding to var[sub] and this
- was fixed. It also fixed ${name} where name is a name reference
- to var[sub].
-07-09-18 It is now legal to create a name reference without an initialization.
- It will be bound to a variable on the first assignment.
-07-08-30 A discipline function can be invoked as ${x.foo} and is equivalent
- to ${ x.foo;} and can be invoked as x.foo inside ((...)).
-07-07-09 A bug in which typeset -a did not list indexed arrays has been
- fixed.
-07-07-03 The command substitution ${ command;} has been added. It behaves
- like $(command) except that command is executed in the current
- shell environment. The ${ must be followed by a blank or an
- operator.
-
-08-04-17 --- Release ksh93s+ ---
-08-04-17 A bug in which umask was not being restored correctly after a
- subshell has been fixed.
-08-04-15 A bug in which sending a STOP signal to a job control shell started
- from within a shell function caused cause the invoking shell to
- terminate has been fixed.
-08-04-11 A bug which caused $(exec > /dev/null) to go into an infinite loop
- has been fixed.
-08-03-27 A bug in which typeset -LZ was being treated as -RZ has been fixed.
-08-03-06 A bug with ksh -P on systems that support the the profile shell,
- in which it would exit after running a non-builtin has been fixed.
-08-01-31 A bug in which command substitution inside ((...)) could cause
- syntax errors or lead to core dumps has been fixed.
-08-01-17 A bug in which discipline functions could be deleted when invoked
- from a subshell has been fixed.
-08-01-17 A bug in which a command substitution consisting only of
- assignments was treated as a noop has been fixed.
-08-01-17 A bug in which discipline functions invoked from withing a
- compound assignment could fail has been fixed.
-08-01-16 Incomplete arithmetic assignments, for example ((x += )), now
- generate an error message.
-08-01-16 A bug in which a set discipline defined for a variable before
- an array assignment could cause a core dump has been fixed.
-08-01-03 A bug in on some systems in which exit status 0 is incorrectly
- returned by a process that catches the SIGCONT signal is stopped
- and then continued.
-07-12-13 A race condition in which a program that has been stopped and then
- continued could loose the exit status has been fixed.
-07-12-12 Code to check for file system out of space write errors for all
- writes has been added.
-07-12-11 A bug in the macro expander for multibyte characters in which
- part of the character contains a file pattern byte has been fixed.
-07-12-06 A bug in the emacs edit mode when multiline was set that output
- a backspace before the newline to the screen has been fixed.
-07-12-04 A bug in which using <n>TAB after a variable name listing expansion
- in the edit modes would cause the $ to disappear has been fixed.
-07-11-28 A bug in which setting IFS to readonly could cause a subsequent
- command substitution to fail has been fixed.
-07-11-27 A work around for a gcc 4.* C99 "feature" that could cause a job
- control shell to go into an infinite loop by adding the volatile
- attribute to some auto vars in functions that call setjmp().
-07-11-27 A bug in which the shell could read ahead on a pipe causing the
- standard input to be incorrectly positioned has been fixed.
-07-11-27 A bug in which compound variable UTF-8 multibyte values were not
- expanded or traced properly has been fixed.
-07-11-21 A bug where an unbalanced '[' in a command argument was not treated
- properly has been fixed.
-07-11-15 A bug in which compatibility mode (no long option names) getopts(1)
- incorrectly set the value of OPTARG for flag options has been fixed.
-07-11-15 A bug in which "hash -- name" treated "--" as an invalid name operand
- has been fixed.
-07-11-15 typeset now handles "-t -- [-r] [--]" for s5r4 hash(1) compatibility.
-07-11-15 A bug in which the umask builtin mis-handled symbolic mode operands
- has been fixed.
-07-11-15 Bugs in which shell arithmetic and the printf builtin mis-handled the
- signs of { -NaN -Inf -0.0 } have been fixed.
-07-11-15 The full { SIGRTMIN SIGRTMIN+1 ... SIGRTMAX-1 SIGRTMAX } range
- of signals, determined at runtime, are now supported.
-07-11-15 A bug in which creating an index array with only subscript 0 created
- only a simple variable has been fixed.
-07-11-14 A bug in which appending to an indexed array using the form
- name+=([sub]=value) could cause the array to become an associative
- array has been fixed.
-07-11-14 A bug in which typeset without arguments could coredump if a
- variable is declared as in indexed array and has no elements has
- been fixed.
-07-11-14 A bug in which creating a local SECONDS variable with typeset in
- a function could corrupt memory has been fixed.
-07-11-14 A bug which could cause a core dump when a script invoked by name
- from a function used compound variables has been fixed.
-07-11-05 A bug in which printf %d "'AB" did not diagnose unconverted characters
- has been fixed.
-07-11-05 printf %g "'A" support added for all floating point formats.
-07-11-01 A bug in which typeset -f fun did not display the function definition
- when invoked in a subshell has been fixed.
-07-10-29 The sleep builtin was fixed so that all floating point constants
- are valid operands.
-07-10-10 A bug in which the locale was not being restored after
- LANG=value command has been fixed.
-07-09-20 A bug in which a nameref to a compound variable that was local
- to the calling function would not expand correctly when displaying
- is value has been fixed.
-07-09-19 A bug which cause cause a core dump if .sh.edchar returned
- 80 characters or more from a keyboard trap has been fixed.
-07-09-14 A bug in which could cause a core dump when more than 8 file
- descriptors were in use has been fixed.
-07-09-10 A bug in which creating a name reference to an instance of
- an array when the array name is itself a reference has been fixed.
-07-09-10 The file completion code has been modified so that after an = in
- any word, each : will be considered a path delimiter.
-07-09-06 A bug in which subprocess cleanup could corrupt the malloc() heap
- has been fixed.
-07-08-26 A bug in which a name reference to an associative array instance
- could cause the subscript to be evaluated as an arithmetic expression
- has been fixed.
-07-08-22 A bug in which the value of an array instance was of a compound
- variable was not expanded correctly has been fixed.
-07-08-14 A bug which could cause a core dump when a compound assignment was
- made to a compound variable element with a typeset -a attribute
- has been fixed.
-07-08-08 A bug in which a trap ignored in a subshell caused it to be
- ignored by the parent has been fixed.
-07-08-07 A bug in which the set command would generated erroneous output
- for a variable with the -RZ attribute if the variable name had been
- passed to a function has been fixed.
-07-08-02 A bug in which read x[1] could core dump has been fixed.
-07-08-02 A second bug in which after read x[sub] into an associative array
- of an element that hasn't been assigned could lead to a core dump
- has been fixed.
-07-07-31 A bug in which a pipeline that completed correctly could have
- an exit status of 127 when pipefail was enabled has been fixed.
-07-07-09 The SHOPT_AUDIT compile option has been added for keyboard logging.
-07-06-25 In vi insert mode, ksh no longer emits a backspace character
- before the carriage return when the newline is entered.
-07-06-25 A bug in which pipefail would cause a command to return 0
- when the pipeline was the last command and the failure happened
- on a component other than the last has been fixed.
-07-06-25 A bug in the expansion of ${var/pattern/rep} when pattern or rep
- contained a left parenthesis in single quotes has been fixed.
-07-06-18 The braces for a subscripted variable with ${var[sub]} are now
- optional when inside [[...]], ((...)) or as a subscript.
-07-05-28 A bug in brace expansion in which single and double quotes did
- not treat the comma as a literal character has been fixed.
-07-05-24 The -p option of whence now disables -v.
-07-05-23 Several bug fixes in compound variables and arrays of arrays
- have been made.
-07-05-15 A bug in which the %B format of printf was affected by the
- locale has been fixed.
-07-05-14 A bug in which \ was not removed in the replacement pattern with
- ${var/pattern/rep} when it was not followed by \ or a digit has
- been fixed.
-07-05-10 A bug in which ksh -R file core dumped if no script was specified
- has been fixed. it not displays an error message.
-07-05-07 Added additional Solaris signals to signal table.
-07-04-30 A bug in which a pipeline with command substitution inside a
- function could cause a pipeline that invokes this function to
- hang when the pipefail option is on has been fixed.
-07-04-30 Added -q to whence.
-07-04-18 A small memory leak with each redirection of a non-builtin has
- been fixed.
-07-03-08 A bug in which set +o output command line options has been fixed.
-07-03-08 A bug in which an error in read (for example, an invalid variable
- name), could leave the terminal in raw mode has been fixed.
-07-03-06 A bug in which read could core dump when specified with an array
- variable with a subscript that is an arithmetic expression has
- been fixed.
-07-03-06 Several serious bugs with the restricted shell were reported and
- fixed.
-07-03-02 If a job is stopped, and subsequently restarted with a CONT
- signal and exits normally, ksh93 was incorrectly exiting with
- the exit status of the stop signal number.
-07-02-26 M-^L added to emacs mode to clear the screen.
-07-02-26 A bug in which setting a variable readonly in a subshell would
- cause an unset error when the subshell completed has been fixed.
-07-02-19 The format with printf uses the new = flag to center the output.
-07-02-19 A bug in which ksh93 did not allow multibyte characters in
- identifier names has been fixed.
-07-02-19 A bug introduced in ksh93 that causes global compound variable
- definitions inside functions to exit with "no parent" has been fixed.
-07-02-19 A bug in which using compound commands in process redirection
- arguments would give syntax errors <(...) and >(...) has been fixed.
-07-01-29 A bug which caused the shell to core dump which can occur when a
- built-in exits without closing files that it opens has been fixed.
-07-01-26 A bug in which ~(E) in patterns containing \ that are not inside ()
- has been fixed.
-
-06-12-29 --- Release ksh93s ---
-06-12-29 A bug in which the value of IFS could be changed after a command
- substitution has been fixed.
-06-12-22 /dev/(tcp|udp|sctp)/HOST/SEVRICE now handles IPv6 addresses on
- systems that provide getaddrinfo(3).
-06-12-19 A -v option was added to read. With this option the value of
- the first variable name argument will become the default value
- when read from a terminal device.
-06-11-20 A bug in which "${foo[@]:1}}" expands a null argument (instead of
- no argument), when foo[0] is not empty has been fixed.
-06-11-16 The discipline functions have been modified to allow each subscript
- to act independently. Currently the discipline function will not
- be called when called from a discipline function of the same variable.
-06-11-14 A bug which could cause a core dump if a file descriptor for
- an internal file was closed from with a subshell has been fixed.
-06-10-30 The redirections <# pattern, and <## pattern have been added.
- Both seek forward to the beginning of the next line that contains
- the pattern. The <## form copies the skipped portion to standard
- output.
-06-10-26 On systems that support stream control transport, the virtual file
- name /dev/sctp/host/port can now be used to establish connections.
-06-10-26 The printf modifier # when used with d produces units in thousands
- with a single letter suffix added. The modifier # when used with
- the i specification provides units of 1024 with a two letter suffix.
-06-10-24 The value of $! is now set to the process id of a job put
- into the background with the bg command as required by POSIX.
-06-10-23 A bug in which the value of $! was affected by a background
- job started from a subshell has been fixed.
-06-10-23 A bug in ${var:offset:len} in multibyte locales has been fixed.
-06-10-15 The remaining math functions from C99 were added for any system
- that supports them.
-06-10-13 The klockwork.com software detected a few coding errors that
- have been fixed.
-06-10-12 A bug when skipping over `...` with ${x:=`...`} when x is set
- has been fixed.
-06-10-11 A bug in process floating constants produced by the %a format
- of printf has been fixed.
-06-10-06 A bug in which IFS was not being restored correctly in some
- cases after a subshell has been fixed.
-06-10-06 A bug in which pipefail was not detecting some failures in
- pipelines with 3 or more states has been fixed.
-06-10-03 A bug in the processing of >(...) with builtins which could
- cause the builtin to hang has been fixed.
-06-10-03 A bug in the for loop optimizer which causes >(...) process
- substitution to be ignored has been fixed.
-06-09-17 The -a option was added to typeset for indexed arrays. This
- is only needed when using the ([subscript]=value ...) form.
-06-09-06 The showme option was added. Each simple command not beginning
- with a redirection and not occurring with in the while, until, if,
- select condition can be preceded by a semi-colon which will
- be ignored when showme is off. When showme is on, any command
- preceded by a colon will be traced but not executed.
-06-08-16 As a new feature, a leading ~(N) on a pattern has no effect
- except when used for file expansion. In this case if not
- matches are found, the pattern is replaced by nothing rather
- than itself.
-06-08-11 A bug in the expansion of ${.sh.match[i]:${#.shmatch[i]}} has
- been fixed.
-06-08-10 The read builtin options -n and -N have been modified to treat
- the size as characters rather than bytes unless storing into a
- binary (typeset -B) variable.
-06-07-27 When the here document operator << is followed directly by a #
- rather than a -, the first line of the here-document determines
- how much whitespace is removed for each line.
-06-07-26 A bug in the C-shell history (enabled with set -H) in which the
- history event !$ was not processed has been fixed.
-06-07-21 A bug on some systems in which assigning PATH on a command line
- would not take effect has been fixed.
-06-07-20 Add ksh93 and rksh93 as allowable names for ksh binaries.
-06-07-20 Removed the SHOPT_OO compilation option which was only partially
- implemented.
-06-07-20 The ability to use egrep, grep, and fgrep expressions within
- shell patterns has been documented.
-06-07-17 A bug with arithmetic command expressions for locales in which
- the comma is a thousands separator has been fixed.
-06-07-13 The default HISTSIZE was increased from 128 to 512.
-06-07-13 A multibyte problem with locales that use shift codes has been fixed.
-06-06-23 A number of bug fixes for command, file, and variable completion
- have been mode.
-06-06-20 Floating point division by zero now yields the constant Inf or -Inf
- and floating functions with invalid arguments yield NaN.
-06-06-20 The floating point constants Inf and NaN can be used in arithmetic
- expressions.
-06-06-20 The functions isinf(), isnan(), tanhl() have been added for
- arithmetic expressions.
-06-06-13 Internal change to use ordering for variables instead of hashing
- to speed up prefix matching.
-06-06-13 A window between fork/exec in which a signal could get lost
- and cause a program to hang has been eliminated
-06-06-13 A bug in edit completion with quoted strings has been fixed.
-06-06-07 The restricted options can now be enabled by set as well as on
- the command line. Once set, it can not be disabled.
-06-06-04 Modified built-in binding so that for systems for which /bin
- and /usr/bin are the same, a builtin bound to /bin will get
- selected when either /bin or /usr/bin is scanned.
-06-06-04 Added literal-next character processing for emacs/gmacs mode.
- This change is not compatible with earlier versions of ksh93
- and ksh88 when the stty lnext is control-v. The sequence
- escape-control-v will display the shell version.
-06-05-31 Modified emacs and vi mode so that entering a TAB after a partial
- TAB completion, generates a listing of possible completions.
- After the second TAB, a number followed by a TAB will perform
- the completion with the corresponding item.
-06-05-19 Modified arithmetic so that conversions to strings default to
- the maximum number of precision digits.
-06-05-16 Bug fixes for multibyte locales.
-06-05-10 The =~ operator was added to [[...]] and [[ string ~= ERE ]]
- is equivalent to [[ string == ~(E)ERE ]].
-06-04-25 A bug in the vi edit mode which could cause the shell to core dump
- when switching from emacs mode.
-06-04-17 A bug in which using LANG or LC_ in assignment lists with builtins
- did not restore the localed correctly has been fixed.
-06-04-04 A bug in which discipline functions could not be added to variables
- whose names started with .sh has been fixed.
-06-03-28 The -s option to typeset was added to modify -i to indicate short
- integers.
-06-03-28 A bug in which variables assignment lists before functions
- defined with function name were not passed on the functions
- invoked by this function has been fixed.
-06-03-28 A bug in which name references defined within a function defined
- with function name could not be used with compound variables has
- been fixed.
-06-03-27 A bug in which read <&p (print >&p) would cause the coprocess input
- (output) pipe to close before reading from (after writing to)
- it has been fixed.
-06-02-28 A bug in which stopping a job created with the hist builtin command
- would create a job that could not be restarted has been fixed.
-
-06-01-24 --- Release ksh93r ---
-06-01-24 A bug in which running commands with standard output closed would
- not work as expected has been fixed.
-06-01-23 A bug in which print -u<n> could fail when file descriptor <n> was
- open for writing has been fixed.
-06-01-19 The ?: arithmetic operator fixed to work when the operation after
- the colon was an assignment.
-05-12-24 A bug which could lead to a core dump when elements of a compound
- variable were array elements, i.e. foo=(bar=(1 2)), has been fixed.
-05-12-13 An arithmetic bug in which x+=y+=z was not working has been fixed.
-05-12-13 An arithmetic bug in which x||y was returning x when x was non-zero
- rather than 1 has been fixed.
-05-12-07 The aliases for integer and float have been changed to use attributes
- -li and -lE to handle long long and long double types.
-05-12-07 The histexpand (-H) option has been added which allows C-shell
- style history expansions using the history character !.
-05-12-07 The multiline option was added which changes that way the edit
- modes handle lines longer than the window width. Instead of
- horizontal scrolling, multiple lines on the screen are used.
-05-12-05 The whence builtin now returns an absolute pathname when the
- command is found in the current directory.
-05-11-29 A bug which caused ksh -c '[[ ! ((' to core dump rather than
- report a syntax error has been fixed.
-05-11-29 A bug when reading fixed length records into typeset -b variables
- which caused a zero byte to terminate the value has been fixed.
-05-11-22 The ability to seek to an offset within a file has been added
- with the new I/O redirection operators, <# and >#. Currently,
- these redirection operators must be followed by ((expr))
- but in a future release, it should be able to used to seek forward
- to the specified shell pattern. In addition $(n<#) expands to the
- current byte offset for file descriptor n.
-05-11-22 The .sh.match array variable is now set after each [[ ... ]]
- pattern match. Previously it was only set for substring matches.
-05-10-17 A bug in which the library path variable could be prefixed
- with a directory when a .path file was not encountered in
- the directory of the executable has been fixed.
-05-09-15 A for/while loop optimizer bug in which $OPTIND was not
- correctly expanded has been fixed.
-05-09-05 A bug in which a history command that invoked a history
- command could go into an infinite loop has been fixed.
-05-08-31 In the case that IFS contains to adjacent new-lines so that
- new-line is not treated as a space delimiter, only a single
- new-line is deleted at the end of a command substitution.
-05-08-19 When a tilde substitution expands to the / directory and is
- followed by a /, it is replaced by the empty string.
-05-08-16 A bug in which n<&m did not synchronize m has been fixed.
-05-08-16 A bug in which process substitution ( <() and >() ) was not
- working within for and while loops has been fixed.
-05-07-24 A bug in which the pattern ~(E)(foo|bar) was treated as a syntax
- error has been fixed.
-05-07-24 A bug in completion with <n>=, where n was the one of the
- previous selection choices has been fixed.
-05-07-21 A bug with multibyte input when no edit mode was specified which
- caused the input line to shift left/right has been fixed.
-05-06-24 A race condition which could cause the exit status to get lost
- on some fast systems has been fixed.
-05-06-21 A bug in which nested patterns of the form {m,n}(pat) would cause
- syntax errors has been fixed.
-05-06-21 A bug in the macro expander has been fixed which could cause a
- syntax error for an expansion of the form ${x-$(...)} when
- x is set and the command substitution contained certain strings.
-05-06-08 On systems for which echo does not do System V style \ expansions,
- the -e option was added to enable these expansion.
-05-06-08 A bug in which ${var op pattern} to not work when inside an
- arithmetic expression has been fixed.
-05-05-23 An extension to shell patterns that allows matching of nested
- groups while skipping over quoted strings has been added.
-05-05-18 A bug in which the line number for errors was not correct for
- functions loaded from FPATH has been fixed.
-05-04-18 A bug in which the exit status $? is not set when a trap triggered
- by the [[...]] command is executed has been fixed.
-05-04-08 Redirection operators can be directly preceded with {varname}
- with no intervening space, where varname is a variable name which
- allows the shell to select a file descriptor > 10 and store it
- into varname.
-05-04-08 SHOPT_CMDLIB_BLTIN=1 now includes <cmdlist.h> generated table.
-05-04-07 [[ -o ?option ]] is true if "option" is a supported option.
-05-04-05 A bug in handling file completion with spaces in the names
- has been fixed.
-05-03-25 The SIGWINCH signal is caught by default to keeps the LINES and
- COLUMNS variables in sync with the actual window size.
-05-03-25 Building ksh with SHOPT_REMOTE=1 causes ksh to set --rc if stdin is
- a socket (presumably part of a remote shell invocation.)
-05-03-25 Building ksh with SHOPT_SYSRC=1 causes interactive ksh to source
- /etc/ksh.kshrc (if it exists) before sourcing the $ENV file.
-05-03-25 {first..last[..incr][%fmt]} sequences added to brace expansions
- when braceexpand is enabled.
-05-03-03 A bug where a SIGCHLD interrupt could cause a fifo open to fail has
- been fixed.
-05-02-25 A bug in which a builtin command run in the background could
- keep a file descriptor open which could cause a foreground
- process to hang has been fixed.
-05-02-24 A bug where builtin library commands (e.g., date and TZ) failed to
- detect environment variable changes has been fixed.
-05-02-22 The read builtin and word splitting are now consistent with respect
- to IFS -- both treat IFS as field delimiters.
-05-02-22 The read builtin no longer strips off trailing delimiters that
- are not space characters when there are fewer variables than fields.
-05-02-17 A builtin bug on systems where dlsym(libcmd) returns link-time
- bindings has been fixed.
-05-02-12 A bug in which the lib_init() function for .paths BUILTIN_LIB
- libraries was not called has been fixed.
-05-02-06 A bug on some systems in which moving the write end of a co-process
- to a numbered file descriptor could cause it to close has been fixed.
-05-02-06 A bug in the vi-edit mode in which the character under the cursor
- was not deleted in some cases with the d% directive has been fixed.
-05-02-06 A bug where external builtin stdout/stderr redirection corrupted
- stdout has been fixed.
-05-02-04 A bug where times formatting assumed CLK_TCK==60 has been fixed.
-
-05-01-11 --- Release ksh93q ---
-05-01-11 A bug in the integral divide by zero check has been fixed.
-05-01-11 The -l option has been added to read /etc/profile and
- $HOME/.profile, if they exist, before the first command.
-05-01-11 An argument parsing bug that caused `kill -s x -- n' to fail has
- been fixed.
-05-01-11 The .paths file, introduced in ksh93m, which can appear in
- any directory in PATH, now allows a line of the form 'BUILTIN_LIB=.'
- When a command is searched for this directory, and the full path
- matches the path of the built-in version of the command (listed
- by the 'builtin' command) then the built-in version of the command
- is used. When ksh is built with SHOPT_CMDLIB_DIR=1 then all libcmd
- functions become builtins with the '/opt/ast/bin/' directory prefix.
-05-01-10 A bug in which a nameref to a compound name caused a core dump has
- been fixed.
-05-01-09 A bug in which some SIGCHLD interrupts (from child processes exiting)
- caused a fatal print/echo error diagnostic has been fixed.
-04-12-24 A bug in which some SIGCHLD interrupts (from child processes exiting)
- corrupted the internal process/job list, sometimes causing the shell
- to hang, has been fixed.
-04-12-01 A bug in which typeset -Fn truncated less than n digits for large
- numbers has been fixed.
-04-11-25 A bug in which standard error could be closed after a redirection
- to /dev/stderr has been fixed.
-04-11-17 A bug in which an expansion of the form ${array[@]:3} could expand
- to ${array[0]} when ${array[3]} was not set has been fixed.
-04-10-22 The -E or -orc command line option reads ${ENV-$HOME/.kshrc} file.
-04-10-22 `-o foo' equivalent to `+o nofoo', `-o nobar' equivalent to `+o bar'.
- `--foo' equivalent to `-o foo', `--nofoo' equivalent to `+o foo'
-04-10-05 The .paths file, introduced in ksh93m, which can appear in
- any directory in PATH, now allows a line of the form
- 'BUILTIN_LIB=libname'. When a command is searched for this directory,
- the shared library named by libname will first be searched for a
- built-in version of the command.
-04-09-03 <<< here documents now handle quotes in the word token correctly.
-04-08-08 The maximum size for read -n and and read -N was increased from
- 4095 to 32M.
-04-08-04 printf %q was modified so that if an no operand was supplied, no
- no output would be generated rather than a quoted empty string.
-04-08-01 The -n and -N options of the read builtin has been modified
- when reading variables with the binary attribute so that the
- data is stored directly rather than through assignment.
-04-08-01 The shcomp command has been modified to process alias commands
- under some conditions.
-04-07-31 The .sh.match variable added in ksh93l, now works like other
- indexed arrays.
-04-07-08 A loop optimizer bug which occurs when typeset is used in
- a for or while loop inside a function has been fixed.
-04-06-24 The number of subexpressions in a pattern was increased to 64
- from the current number of 20.
-04-06-17 The -t option to read was modified to allow seconds to be
- specified as any arithmetic expression rather than just
- an integral number of seconds, for example even -t 'sin(.5)'
- is now valid.
-04-06-16 Two small memory leak problems were fixed.
-04-06-15 A bug in ${var/pattern/"string"} which occurred when string
- contained pattern matching characters has been fixed.
-04-05-08 printf $'%d\n' produced an erroneous error message and has
- been fixed.
-04-05-24 A bug in which an associative array without any elements could
- cause a core dump when a script with an associative array with
- the same name was declared in a script invoked by name has
- been fixed.
-04-05-11 A bug in which an exec statement could close the script that
- is being processed in a script that is run by name causing
- a failure has been fixed.
-04-04-28 If the first character of assignment to an integer variable was 0,
- the variable had been treated as unsigned. This behavior was
- undocumented and has been removed.
-04-04-05 A bug in which the positioning of standard input could be incorrect
- after reading from standard input from a subshell has been fixed.
-04-03-30 A bug in the for loop optimizer which in rare cases could cause
- memory corruption has been fixed.
-04-03-29 The preset alias source='command .' has been added.
-04-03-29 A bug introduced in ksh93p on some systems in which invoked by
- name with #! on the first line would not get the signals handling
- initialized correctly has been fixed.
-04-03-29 A bug introduced in ksh93p in which a HUP signal received by
- a shell that is a session group leader was not passed down to
- its children has been fixed.
-
-04-02-28 --- Release ksh93p ---
-04-02-28 The ability to apply an append discipline to any variable has
- been added.
-04-02-14 A bug in which the exportall option (set -a) would cause incorrect
- results for arrays has been fixed.
-04-02-02 A bug in which an exported array would pass more than
- the first element to a script invoked by name has been fixed.
-04-02-02 A bug on some systems in which name=value pairs preceding a script
- invoked by name was not getting passed to the script has been fixed.
-04-01-20 A bug in which an unset discipline function could cause a core
- dump on some systems has been fixed.
-04-01-12 A bug in which a continue or break called outside a loop from
- inside a function defined with name() syntax could affect
- the invoking function has been fixed.
-04-01-08 If a command name begins with ~, only filename completion will be
- attempted rather than pathname completion using the builtin editors.
-04-01-08 A bug in the vi edit mode in which the wrong repeat count on
- multiple word replacements with the . directive has been fixed.
-04-01-06 Backspace characters are now handled correctly in prompt strings.
-04-01-06 The getopts builtin has been modified to accept numerical
- arguments of size long long on systems that support this.
-04-01-06 A bug in which unsetting all elements of an associative array
- would cause it to be treated as an indexed array has been fixed.
-03-12-15 A bug in which a quoted string ending with an unescaped $ would
- delete the ending $ in certain cases has been fixed.
-03-12-05 A bug in which the shell could hang when set -x tracing a command
- when an invalid multibyte character is encountered has been fixed.
-03-12-05 On some systems, if the KEYBD trap is set, then commands that use
- the meta key were not processed until return was hit. This
- has been fixed.
-03-12-05 A problem which occurred when the login shell was not a group
- leader that could cause it to fail has been fixed.
-03-12-05 A problem in which a shell could core dump after receiving a signal
- that should cause it to terminate while it was in the process
- of acquiring more space has been fixed.
-03-12-05 If ENV is not specified, the shell will default to $HOME/.kshrc
- for interactive shells.
-03-11-21 A bug introduced in ksh93o in which the DEBUG trap could get
- disabled after it triggered has been fixed.
-03-11-04 A bug in which using arithmetic prefix operators ++ or -- on a
- non-lvalue could cause a core dump has been fixed.
-03-11-04 A bug in which leading zeros were stripped from variable
- expansions within arithmetic computation to avoid being treated
- as octal constants when they should not have, has been fixed.
-03-10-08 A bug introduced in ksh93o in which a large here document inside
- a function definition could get corrupted has been fixed.
-03-09-22 A bug in which the .get discipline function was not being
- called when a string variable was implicitly referenced from
- within a numerical expression has been fixed.
-03-09-22 A bug in which a script without a leading #! could get executed
- by /bin/sh rather than the current shell on some systems has
- been fixed.
-03-09-12 To improve conformance with ksh88, leading zeros will be ignored
- when getting the numerical value of a string variable so that
- they will not be treated as octal constants.
-03-09-03 The builtin kill command now processes obsolete invocations
- such as kill -1 -pid.
-03-09-02 The restriction on modifying FPATH in a restricted shell (sh -r)
- has been documented.
-03-09-02 The restricted shell (sh -r) has been modified to disallow
- executing command -p.
-03-08-07 A bug in which the KEYBD trap was not being invoked when
- characters with the 8th bit set has been fixed.
-03-08-02 A parser bug introduced in ksh93o which caused the character
- after () in a Posix function definition to be skipped
- when reading from standard input has been fixed.
-03-08-01 A bug in which "${foo#pattern}(x)" treated (x) as if it were
- part of the pattern has been fixed.
-03-08-01 The command -x option has been modified so that any trailing
- arguments that do expand to a single word will be included
- on each invocation, so that commands like command -x mv * dir
- work as expected.
-
-03-07-20 --- Release ksh93o+ ---
-03-07-20 A bug in which could cause memory corruption when a posix
- function invoked another one has been fixed.
-03-07-15 A bug in which a file descriptor>2 could be closed before
- executing a script has been fixed.
-03-07-15 A parsing error for <() and >() process substitutions inside
- command substitution has been fixed.
-03-07-15 A parsing error for patterns of the form {...}(...) when
- used inside ${...} has been fixed.
-03-07-15 An error in which expanding an indexed array inside a compound
- variable could cause a core dump has been fixed.
-03-07-15 A bug in which on rare occasions a job completion interrupt
- could cause to core dump has been fixed.
-03-06-26 A bug in which process substitution embedded within command
- substitution would generate a syntax error has been fixed.
-03-96-23 A bug in which ${@:offset:len} could core dump when there
- were no arguments has been fixed.
-03-96-23 A bug in which ${X[@]:offset:len} could core dump when X
- was unset has been fixed.
-03-06-22 The -x option was added to the command builtin. If this
- option is on, and the number of arguments would exceed ARG_MAX,
- the command will be invoked multiple times with a subset of
- the arguments. For example, with alias grep='command -x grep,
- any number of arguments can be specified.
-03-06-14 A bug in which could cause a core dump on some systems with
- vi and emacs editors with the MULTIBYTE option has been fixed.
-03-06-06 A bug in which the shell could core dump when a script was
- run from its directory, and the script name a symlink to a file
- beginning with .., has been fixed.
-03-06-05 A bug in which the shell could core dump when a child process
- that it is unaware of terminates while it is calling malloc()
- has been fixed.
-03-06-02 An option named globstar (set -G) has been added. When enabled,
- during pathname expansion, any component that consists only of ** is
- matches all files and any number of directory levels.
-03-05-30 A bug in which the PATH search could give incorrect results when
- run from directory foo and PATH contained .:foo:xxx has been fixed.
-03-05-29 Some changes were made to the code that displays the prompt in edit
- mode to better handle escape sequences in the prompt.
-03-05-27 I added = to the list of characters that mark the beginning of
- a word for edit completion so that filenames in assignments
- can be completed.
-03-05-20 A bug in which read -N could hang on some systems when reading
- from a terminal or a pipe has been fixed.
-03-05-19 A bug in which the output of uname from a command substitution
- would go to the standard output of the invoking command when
- uname was invoked with a non-standard option has been fixed.
-03-05-19 A job control bug which would cause the shell to exit because
- it hadn't take back the terminal has been fixed. The bug
- could occur when running a function that contained a pipeline
- whose last element was a function.
-03-05-19 A job control timing bug introduced in ksh93o on some systems
- which could cause a pipeline to hang if the first component
- completed quickly has been fixed.
-03-05-13 The read builtin has been modified so that the builtin editors
- will not overwrite output from a previous incomplete line.
-03-05-13 A bug in which the name of an identifier could have the string
- .sh. prefixed to it after expanding a variable whose name begins
- with .sh. has been fixed.
-03-05-13 A bug in the expansion of $var for compound variables in which
- some elements would not be output when the name was a prefix
- of another name in the compound variable has been fixed.
-03-05-08 The last item in the ksh93o release on 03-01-02 has been
- altered slightly to preserve the leading 0's when the
- preceding character is a digit. Thus, with typeset -LZ3 x=10,
- $(( 1$x)) will be 1010 whereas $(( $x) will be 10.
-03-04-25 A bug in which if x is a name reference, then nameref y=x.foo
- did not follow x has been fixed.
-
-03-03-18 --- Release ksh93o ---
-03-03-18 A -N unary operator was added to test and [[...]] which returns
- true if the file exists and the file has been modified since it
- was last read.
-03-03-18 The TIMEFORMAT variable was added to control the format for
- the time compound command. The formatting description is
- described in the man page.
-03-03-06 A -N n option was added to read which causes exactly n bytes
- to be read unlike -n n which causes at most n bytes to be read.
-03-03-03 Three new shell variables were added. The variable .sh.file
- stores the full pathname of the file that the current command
- was found in. The variable .sh.fun names the current function
- that is running. The variable .sh.subshell contains the depth
- of the current subshell or command substitution.
-03-03-03 When the DEBUG trap is executed, the current command line after
- expansions is placed in the variable .sh.command. The trap
- is also now triggered before each iteration of a for, select,
- and case command and before each assignment and redirection.
-03-02-28 Function definitions are no longer stored in the history file so
- that set -o nolog no longer has any meaning.
-03-02-28 All function definitions can be displayed with typeset -f not
- just those stored in the history file. In addition, typeset +f
- displays the function name followed by a comment containing the
- line number and the path name for the file that defined this function.
-03-02-28 A bug in which the value of $LINENO was not correct when executing
- command contained inside mult-line command substitutions has been
- fixed.
-03-02-19 Since some existing ksh88 scripts use the undocumented and
- unintended ability to insert a : in front of the % and # parameter
- expansion operators, ksh93 was modified to accept :% as equivalent
- to % and :# as equivalent to # with ${name op word}.
-03-02-14 A bug which could cause a core dump when reading from standard
- error when standard error was a pty has been fixed.
-03-02-14 The shell arithmetic was modified to use long double on systems
- that provide this data type.
-03-02-09 A bug in which a function located in the first directory in FPATH
- would not be found when the last component of PATH was . and the
- current directory was one of the directories in PATH has been fixed.
-03-02-07 The trap and kill builtin commands now accept a leading SIG prefix
- on the signal names as documented.
-03-02-05 A bug in the expansion of ${var/$pattern}, when pattern contained
- \[ has been fixed.
-03-02-05 A bug in which .sh.match[n], n>0, was not being set for substring
- matches with % and %% has been fixed.
-03-01-15 A bug in which getopts did not work for numerical arguments specified
- as n#var in the getopts string has been fixed.
-03-01-09 A bug in which using ${.sh.match} multiple times could lead to
- a memory exception has been fixed.
-03-01-06 A bug in the expansion of ${var/pattern/$string} in the case that
- $string contains \digit has been fixed.
-03-01-02 A -P option was added for systems such as Solaris 8 that support
- profile shell.
-03-01-02 For backward compatibility with ksh88, arithmetic expansion
- with ((...)) and let has been modified so that if x is a zero-filled
- variable, $x will not be treated as an octal constant.
-
-02-12-05 --- Release ksh93n+ ---
-02-11-30 A bug that can show up in evaluating arithmetic statements that
- are in an autoloaded function when the function is autoload from
- another function has been fixed.
-02-11-30 An optimization bug in which an expansion of the form ${!name.@},
- which occurred inside a for or a while loop, when name is a name
- reference, has been fixed.
-02-11-18 A bug in which modifying array variables in a subshell could leave
- side effects in the parent shell environment has been fixed.
-02-11-18 A memory leak when unsetting an associative array has been fixed.
-02-11-14 The code to display compound objects was rewritten to make
- it easier for runtime extensions to reuse this code.
-02-11-14 A change was made to allow runtime builtins to be notified when
- a signal is received so that cleanup can be performed.
-02-10-31 User applications can now trap the ALRM signal. Previously,
- the ALRM signal was used internally and could not be used
- by applications.
-02-10-31 A bug in which signals received while reading from a coprocess
- for which traps were set was not handled correctly has been fixed.
-02-10-31 A bug in which a file opened with exec inside a subshell could
- be closed before the subshell completed has been fixed.
-02-10-21 A bug in which setting PATH or FPATH inside a function might not
- take effect has been fixed.
-02-10-21 A bug which could cause a core dump when a local SECONDS variable
- is defined in a function has been fixed.
-02-10-15 A bug in which the associate array name operator ${!array[@]}
- could return the same name multiple times has been fixed.
-02-10-15 A bug in which the zero'th element of an associative array was
- not getting set when an assignment was made without a subscript
- specified has been fixed.
-
-02-09-30 --- Release ksh93n ---
-02-09-30 The maximum indexed array size was increased to 16Megs.
-02-09-30 A bug which could cause a core dump when changing attributes
- of associative array has been fixed.
-02-09-30 A bug in which exporting an array variable would not export the
- 0-th element has been fixed.
-02-09-30 A bug in which an array assignment of the form a=($a ...) would unset
- 'a' before the right hand side was evaluated has been fixed.
-02-09-27 A bug in which the error message for ${var?message} when var was
- null or unset did not contain the variable name var has been fixed.
-02-09-27 A bug in which closing file descriptors 0 through 2 could
- cause a subsequent here document to fail has been fixed.
-02-09-14 A bug in whence which occurs when the specified name contained
- a / has been fixed.
-02-09-14 A bug in the parser for strings of the form name$((expr))=value
- has been fixed.
-02-09-14 A for loop optimization bug in which the number of elements in
- an array was treated as an invariant has been fixed.
-02-09-09 A bug in which redirection or closing of a file descriptor between
- 3 and 9 could cause a subsequent here document to fail has been
- fixed.
-02-09-09 A bug in which a background job was not removed from the job list
- when a subshell completed has been fixed, for example (prog&).
-02-09-03 A bug in which an assignment of the form name=(integer x=3)
- could be interpretted as an array assignment rather than a
- compound variable assignment has been fixed.
-02-08-19 A command completion bug which occurred on file systems that
- are case insensitive has been fixed.
-02-08-19 A bug which could lead to an exception on some systems (for
- example FREEBSD) which occurred when setting PATH has been fixed.
-02-08-11 A bug in arithmetic rounding in which a value input as a decimal
- string would output as a rounded version of the string has
- been fixed.
-02-08-11 A bug in which the last character could be deleted from shell
- traces and from whence when called from a multibyte locale
- has been fixed.
-02-08-01 A bug which could cause a core dump to occur when a shell script
- is executed while a coprocess is running that has closed the
- output pipe has been fixed.
-02-08-01 A bug in which command completion in multibyte mode could
- corrupt memory for long command lines has been fixed.
-
-02-06-17 --- Release ksh93n- ---
-02-06-17 A bug in which user defined macros could cause a core dump in
- with MULTIBYTE mode has been fixed.
-02-06-17 A bug in which printf format specifiers of the form %2$s were causing
- a core dump has been fixed.
-02-06-17 A bug in which setting stty to noecho mode did not prevent the
- echoing of characters by ksh when emacs or viraw mode
- was enabled has been fixed.
-02-06-17 A bug in which background job completion could cause the sleep
- builtin to terminate prematurely has been fixed.
-02-06-17 A bug in which the shell could core dump if getopts was called
- when the OPTIND variable contained a negative value has been fixed.
-02-06-10 The edit mode prompt has been modified to handle escape sequences.
-02-06-10 A bug which occurred for interactive shells in which the builtin
- cat command was used in command substitution on a file whose
- size was larger than PIPE_BUF has been fixed.
-02-06-10 A bug in which the trap on ERR was not being processed when
- set inside a function has been fixed.
-02-06-07 A bug in which function definitions could cause the history count
- to be decremented by one (and even become negative) has been fixed.
-02-06-05 A bug in read in which share mode could be enabled has been fixed.
-02-05-28 A bug which could occur when the last command of a script was
- a case statement and the action selected ended in ;& instead of ;;
- has been fixed.
-02-05-23 A bug with unary + introduced in ksh93k has been fixed.
-02-05-07 A bug in substitutions of the form ${var/pattern/string} in which
- a backslash was inserted in the replacement string when it contained
- a special pattern character has been fixed.
-02-05-01 A bug in the emacs edit mode which occurred in versions compiled
- for multibyte character sets which occurred when a repeated search
- was requested after a long line had been returned for the previous
- search has been fixed.
-02-04-02 vi and emacs edit modes were modified so that tab completion is
- disabled when invoked from the read built-in.
-
-02-03-26 --- Release ksh93m+ ---
-02-03-26 A bug in which \ was not handled correctly when used in file
- expansion has been fixed.
-02-02-18 A bug in which lines beginning with a # were deleted from here
- documents when the here-document delimiter was followed by
- a comment has been fixed.
-02-12-06 An optimization bug in which ${!x[@]) was treated as invariant in
- a for loop has been fixed.
-02-02-06 A bug in which the ERR trap is not cleared for a script invoked
- by name from within a function has been fixed.
-02-01-08 A bug in which a shell script executed from within a subshell
- could cause this script to have an invalid pointer leading
- to a memory fault has been fixed.
-02-01-07 Added here documents of the form <<< word (as per zsh) which
- is equivalent to << delim\nword\ndelim.
-02-01-07 A bug in which the first word of a compound assignment,
- x=(word ...), was treated as a reserved word has been fixed.
-02-01-07 A bug in the handling of \ when noglob was enabled and a
- substitution of the form ${word op pattern} occurred in the
- same word has been fixed.
-02-01-07 A compilation option, CMDLIB_BLTIN in the file OPTION, has
- been added. When this options is set, all commands implemented
- in libcmd become shell builtin commands by default.
-02-01-07 A bug in which builtin foo, where foo is already a builtin
- would result in the builtin foo getting removed has been fixed.
-02-01-07 A bug which the shell executed a command found in the current
- directory when PATH have no valid directories has been fixed.
-01-11-28 The value of $? was not being set when called with exit.
-01-11-28 If the last command was of the form (...) and a trap on EXIT or
- ERR was set, and the command inside () modified the trap, then
- the original trap wasn't executed.
-01-11-26 The value for 0 is now preceded by the base number when
- the base was not 10.
-01-11-26 The default has compilation mode has been changes so that
- viraw mode will always be on.
-
-01-10-31 --- Release ksh93m ---
-01-10-31 A for loop optimizer bug for subshells contained withing for
- loops has been fixed.
-01-10-16 typeset without arguments no longer outputs variable names
- that do not have any attributes that are set.
-01-10-16 A bug introduced in ksh93l in which assignments specified with
- the exec built-in were not being expanded properly has been
- fixed.
-01-10-11 An optimization bug in which ${!x) was treated as invariant in
- a for loop has been fixed.
-01-10-11 Unsigned integer variables in bases other than 10 are printed now
- expand in that base with the base prefix.
-01-10-10 A number of typos in the self generating man pages for shell
- built-ins have been fixed.
-01-10-04 The self generated man pages for hist and fc were not working
- correctly and have been fixed.
-01-10-03 Yet another optimizer bug in which shell patterns were
- treated as invariants has been fixed.
-01-09-27 Two bugs relating to multibyte history searches and to find
- have been fixed.
-01-09-27 A bug introduced in ksh93k in which the PATH searching was
- not restored after running a command with an assignment list
- has been fixed.
-01-09-26 A bug in which a zero filled field was treated as octal when
- converted to integer has been fixed.
-01-09-26 Yet another bug in the optimization of for loops related to
- recursive functions with break or continue statements has been fixed.
-01-09-25 The exponentiation operator ** was added to the shell arithmetic
- evaluation. It has higher precedence than * and is left
- associative.
-01-09-25 The code was modified to use the ast multibyte macros
- and functions for handing multibyte locales.
-01-09-25 The expansion ${parameter:offset:length} now handles negative
- offsets which cause offsets to be measured from the end.
-01-09-25 Some spelling errors in the documentation were corrected.
-01-09-24 The /dev/tcp/host/port and /dev/udp/host/port now allow
- the ports to be specified by service name.
-01-09-24 The change staring with ksh93g in which the the appropriate
- library path variable is prepended with a corresponding library
- directory has been modified. With the new method, only the
- library path defined in the file named .paths in the directory
- where the executable is found will be modified. See the
- man page for more details.
-01-09-23 The .fpath file (see ksh93h) is no longer looked for in each
- directory on the path to locate function directories. The
- file named .paths is used instead.
-01-09-23 A bug in which IFS was not being restored after being changed in
- a subshell has been fixed.
-01-09-16 With the vi and emacs edit modes, after a list of command
- or functions is generated with = or M-= respectively,
- any element from the list can be pasted on the command line
- by preceding the = or M-= with a numeric parameter specifying
- the position on the list.
-01-09-16 A bug in ksh93l caused command completion not to find aliases
- and functions. Command listing from the edit mode was presented
- in reverse order. This has been fixed.
-01-09-13 Another bug in the optimization of for loops related to subshells
- when traps were set has been fixed.
-01-09-07 A change in ksh93l caused brace expansion to stop working
- and this has been fixed.
-01-09-04 A bug introduced in ksh93k in which an arithmetic statement
- within a function that used name references did not follow the
- reference has been fixed.
-01-09-04 A bug introduced in ksh93l in which export -p did not prefix
- each export with the word export has been fixed.
-01-08-29 A bug in multibyte input which occurred when a partial multibyte
- character was received has been fixed.
-01-08-29 A bug introduced in ksh93l which could cause a core dump
- when an assignment list containing PATH is specified inside
- command substitution has been fixed.
-01-08-09 Another bug in the optimization of for loops in ksh93l caused
- errors in recursive functions using local variables that
- contained for loops has been fixed.
-01-07-27 A bug in which IFS would be unset after a command substitution
- inside a here document has been fixed.
-01-07-26 To conform to the POSIX standard, if you invoked ksh name,
- and name does not contain a /, it will first try to run
- one in the current directory whether it is executable or not
- before doing a path search for an executable script. Earlier
- versions first checked for an executable script using the
- PATH variable.
-01-07-23 A bug in which unset -f invoked in a subshell could unset a
- function defined in the parent has been fixed.
-01-07-16 A bug in the optimization of for loops in ksh93l caused
- name references to be treated as invariants has been fixed.
-01-07-09 A bug in which a discipline function applied to a local variable
- could cause a shell exception has been fixed. Discipline
- functions can only be specified for global variables.
-
-01-06-18 --- Release ksh93l ---
-01-06-18 A bug in assigning integers larger than can be represented as
- long integers to floating point variables has been fixed.
-01-06-18 A bug in the handling of unsigned integers (typeset -ui) has
- been fixed.
-01-06-04 The evaluation of the PS1 prompt no longer effects the value
- of the $? variable.
-01-06-01 A small memory leak from subshells has been fixed.
-01-05-22 A bug in which attributes for variables that did not have
- values would be lost after a subshell has been fixed.
-01-05-22 The %R format has been added to convert a shell pattern into
- an extended regular expression.
-01-05-22 The escape sequences \e, \cX, \C[.collating-element.], and
- \x{hex} have been added to ASCII-C strings and to printf format
- strings.
-01-05-20 Patterns of the form {n}(pattern) and {m,n}(pattern) are now
- recognized. The first form matches exactly n of pattern whereas,
- the second form matches from m to n instances of pattern.
-01-05-20 The shell allows *-(pattern), +-(pattern), ?-(pattern),
- {m,n}-(pattern}, and @-(pattern) to cause the minimal
- match of pattern to be selected whenever possible rather
- than the maximal (greedy) match.
-01-05-20 The character class [:word:] has been added to patterns.
- The word class is the union of [:alnum:] and the character _.
-01-05-20 Inside (...) pattern groups, the \ character is now treated
- specially even when in an enclosing character class. The
- sequences, \w, \d, \s are equivalent to the character classes
- word, digit, and space respectively. The sequences \W, \D,
- and \S are their complement sets.
-01-05-20 The shell now recognizes pattern groups of the form
- ~(options:pattern) where options or :pattern can be omitted.
- Options use the letters + and - to enable and disable options
- respectively. The option letters g (greedy), i (ignore case)
- are used to cause maximal matching and to cause case
- insensitive matching respectively. If :pattern is also
- specified, these options are only in effect while this
- pattern is being processed. Otherwise, these options remain
- in effect until the end of the pattern group that they are contained
- in or until another ~(...) is encountered. These pattern groups
- are not counted with respect to group numbering.
-01-05-14 When edit completion, expansion, or listing occurs in the
- middle of a quoted string, the leading quote is ignored when
- performing the completion, expansion, or listing.
-01-05-14 A small memory leak from subshells has been fixed.
-01-05-10 A bug in which open files were not restored after a subshell
- that had used exec to replace a file has been fixed.
-01-05-10 Redirection to a null file name now generates an error message.
-01-05-09 The shell now rejects some invalid parameter substitutions that
- were previously processed in undefined ways.
-01-05-09 A bug in which the output of select was not flushed before the
- read when input did not come from the terminal has been fixed.
-01-05-08 A bug in which job ids would not be freed for interactive shells
- when subshells ran built-ins in the background has been fixed.
-01-05-08 The FPATH variable now requires an explicit . to cause the
- current directory to be treated as a function directory.
-01-05-08 A bug in read -n when echo mode was disabled has been fixed.
-01-05-07 A bug in which function definitions could be listed as part
- of the history has been fixed.
-01-04-30 This release uses a new and often much faster pattern matcher than
- earlier releases.
-01-04-30 An optimizer now eliminates invariant parameter expansions from
- for while and until loops.
-01-04-30 The variable .sh.match is set after each pattern match (# % or /)
- in a variable substitution. The variable .sh.match is an
- indexed array with element 0 being the complete match.
- The array is only valid until the next subsequent pattern
- match or until the value of the variable changes which ever
- comes first.
-01-04-30 A self generating man page has been added to shcomp. Also,
- shcomp now stops compiling when it finds an exit or exec
- command and copies the remainder so that it can be used
- for standard input.
-01-04-30 The shcomp command was modified so that it can work in an
- EBCIDIC environment and that binary scripts are portable
- across environments.
-01-04-30 A bug in the handling of a trailing : in PATH has been fixed.
-01-04-30 A bug in which the builtin version of a command would get invoked
- even though the full pathname for the command was specified
- has been fixed.
-01-04-30 A bug in which read would loose the last character when
- reading the last line of a file that did not contain a new-line
- character has been fixed.
-01-04-23 A bug on some systems in which in vi mode the end of file
- character and end of line character could be swapped has
- been fixed.
-01-04-23 A bug on some systems in which invoking a shell script that
- did not have execute permission could set the exit value to
- 127 rather than 126 has been fixed.
-01-04-20 A bug in which read -n from a pipe would block if fewer than
- n characters was received has been fixed.
-01-04-09 A bug in which invalid patterns, for example, ) by itself,
- was not treated as a string has been fixed so that if i=')',
- then [[ $i == $i ]] is true.
-01-04-09 The shell arithmetic now interprets C character constants.
-01-04-09 A bug in which a non-zero return from a function defined
- with the function reserved word did not trigger the ERR
- trap or exit with set -e has been fixed.
-01-04-02 A bug on some systems, in which characters above 127 were
- not displayed correctly in vi or emacs edit mode has been fixed.
-01-04-02 A bug on some systems, introduced in the 'k' point release, in
- which the erase character in viraw mode was moving the cursor
- to the left without erasing the character has been fixed.
-01-04-02 On some systems the wcwith() function was returning a wrong
- value for characters and caused characters to be displayed
- incorrectly from the shell edit modes. A work around for
- this problem has been added.
-01-03-26 A bug in which valid scripts could produce syntax errors
- when run with locales that considered characters such as "'"
- to be space characters has been fixed.
-01-03-20 A bug in which an syntax error in an arithmetic expression
- entered interactively could cause the shell to go into
- an infinite loop outputting the error message has been fixed.
-01-03-10 ksh93 accepts -l as a synonym for -L in test on systems for
- which /bin/test -l tests for symbolic links.
-01-03-10 A bug in parsing scripts in which { and } are used in place of
- in and esac in case statements embedded in compound commands
- has been fixed. Use of { and } for in and esac is obsolete.
-01-03-06 A bug in which an argument of the form foo=bar was not
- being passed correctly to a traced function whose name
- was foo has been fixed.
-01-03-02 Using $(trap -p name) did not print the name of the current
- trap setting for trap name.
-01-02-26 Exported floating point variables gave incorrect results
- when passing them to ksh88. This has been fixed.
-01-02-25 A race condition in which a coprocess which completed too quickly
- would not allow subsequent coprocesses to start has been fixed.
-01-02-25 The 'g' format specifier is now handled by printf. It had
- inadvertently been omitted.
-01-02-20 The + was not being displayed during an execution trace
- with the += assignment operator.
-01-02-19 The error message which occurs when the interpreter name
- defined on the #! line does not exist is more informative.
-01-02-19 A bug in which $0 would not be set correctly when a
- script with #! was invoked by full pathname from the
- directory of the script has been fixed.
-01-02-19 A shell script did not always pick up tty mode changes
- made by external commands such as stty which could
- effect the behavior of read.
-01-02-19 The -u, -g, and -k unary tests did not give the correct
- results when used with negation and this has been fixed.
-
-01-02-05 --- Release ksh93k+ ---
-01-02-05 The sequence \<newline> inside $'...' was not incrementing
- the line count and this has been fixed.
-01-02-05 Modified expansion of "${@-}" so that if no arguments are set
- it results in null string rather than nothing.
-01-02-02 memory leak problem with local variables in functions fixed.
-01-01-25 allow arithmetic expressions with float%int and treat them
- as ((int)float)%int rather than as an error.
-01-01-19 read -n1 was not working and has been fixed.
-01-01-17 ksh now handles the case in which a here document in command
- substitution $() is terminated by the trailing ). Previously,
- a new-line was needed at the end of the delimiter word.
-01-01-02 A bug in which a KEYBD trap would cause a multi-line token
- to be processed incorrectly has been fixed.
-00-12-10 Arithmetic integer constants can now have L and U suffices.
-00-12-10 A bug in the processing of arithmetic expressions with compound
- variables when the -n option is on has been fixed.
-00-12-08 A bug in M-f and M-b from emacs mode has been fixed. This
- bug only occurs when ksh93 is compiled without MULTIBYTE enabled.
-00-11-29 A bug in which jobs -p would yield 0 for background
- jobs run in a script has been fixed.
-00-11-21 A bug in integer arrays in which the number of elements is
- incorrect when the ++ operator is applied to a non-existing
- element has been fixed. For example, integer x; ((x[3]++)).
-00-11-20 A timing bug in which the shell could reset the terminal
- group to the wrong value in the case that the a new process
- changes the terminal group during startup has been fixed.
-
-00-10-27 --- Release ksh93k ---
-00-10-27 Using tab for completion now works only when applied
- after a non-blank character at the end of the current line.
- In other case a tab is inserted.
-00-10-27 A bug in the emacs edit mode for ^X^E has been fixed.
- The ^X^E sequence is supposed to invoke the full editor
- on the current command.
-00-10-18 A bug in which expansions of the form ${var//pattern/string}
- did not work correctly when pattern was '/' or "/" has
- been fixed.
-00-10-18 The output format for indexed arrays in compound variables
- has been modified so that it can be used as input.
-00-10-18 Assignments with name references (typeset -n) will now
- implicitly unreference an existing name reference.
-00-10-17 A bug the += append operator when a single array element
- is appended to a variable that is not an array has been fixed.
-00-10-16 A bug in which the SIGCONT signal was being sent to
- each process will kill -0 or kill -n 0 has been fixed.
-00-10-12 The arithmetic evaluation portion has been rewritten to
- perform a number of optimizations.
-00-10-10 A bug in which name prefix matching ${!name.*} was not
- checking name to see if it was a name reference has been fixed.
-00-09-26 A bug in the multibyte version in which the width of for
- non-printing characters was not correct has been fixed.
-00-09-12 Made changes to get multibyte editing work on UWIN for windows
-00-09-12 A bug in which multibyte characters would be displayed incorrectly
- has been fixed.
-00-08-08 Removed build dependency on iswprint() and iswalph().
-00-07-20 In some cases the read builtin would read more than a single
- line from a pipe on standard input and therefore leave the seek
- position in the wrong location.
-00-07-05 If the directory / is on the path, a / will not be inserted
- between the directory and the file name during path searching
- to avoid searching // for systems that treat this specially.
-00-06-26 A bug in which on rare occasions wait could return before all
- jobs have completed has been fixed.
-00-06-21 A bug in which backspace did not work correctly during the
- R replace directive in vi-mode has been fixed.
-00-06-12 Added variable name completion/expansion/listing to the set of
- completions. Variable name completions begin with $ or "$ followed
- by a letter.
-00-05-09 --- Release ksh93j ---
-00-05-09 Modified command substitution to avoid using /tmp files when
- run on read-only file systems.
-00-04-17 Modified printf to handle '%..Xc' and '%..Xs' options where X
- is not an alpha character. Previous versions core dumped with this.
-00-04-10 Changes to multibyte editing code were made to use standard
- ISO C functions rather than methods devised before the standard.
-00-04-09 Add %H options to printf to output strings with <"'&\t> properly
- converted for use in HTML and XML documents.
-00-04-07 Modified getopts builtin to handle \f...\f in usage string
- by invoking specified function.
-00-04-04 Added self generating man pages for bg, fc, fg, disown, jobs,
- hist, let, ., and ulimit.
-00-03-30 The append operator += has been added and can be used
- for all assignments, strings, arrays, and compound variables.
-00-03-30 Code was modified in several places to support automatic
- generation of C locale dictionaries.
-00-03-28 A bug in which the set and trap commands invoked with --name
- type arguments would terminate the invoking script has
- been fixed.
-00-03-27 A bug in which the library path variable was not updated
- correctly on some systems as described in the 'g' point
- release has been fixed.
-00-03-07 printf now returns a non-zero exit status when one of
- its arguments cannot be converted to the given type.
-00-03-05 The return value and error message for a command that
- was found on the path but was not executable was set
- incorrectly.
-00-03-05 A prototype for ioctl() was removed from the vi edit mode.
-
-00-01-28 --- Release ksh93i ---
-00-01-28 Most of the built-in commands and ksh itself are now
- self documenting. Running command --man will produce
- screen output. Running command --html produces the
- man page in html format.
-00-01-28 The getopts builtin can process command description
- strings to produce man pages.
-00-01-28 A bug in which a script could terminate when getopts
- encountered an error when invoked inside a function
- has been fixed.
-00-01-28 When a symbolic link was specified as the name of
- the script to invoke by name, the value of $0 was
- set to the real file name rather than the link name
- in some cases and this has been fixed.
-00-01-28 A bug in which the precision given as an argument
- to printf was not working has been fixed.
-
-99-03-31 --- Release ksh93h ---
-99-03-31 The PATH search algorithm has been modified to look
- for a file named .fpath in each bin directory and if
- found, to search for functions in this directory if
- it cannot find the command in that directory.
-99-03-31 When performing pathname expansion, the shell checks
- to see whether each directory it reads is case sensitive
- or not, and performs the matching accordingly.
-99-03-31 The %T format for printing formatted date/time.
-99-03-31 The emacs and vi modes now handle arrow keys when
- they use standard ANSI escape sequences.
-99-03-31 The TAB key can be used for completion in emacs and viraw mode.
-99-03-31 A bug in setting .sh.editchar during the KEYBD trap
- for the MULTIBYTE option was fixed in release ksh93h.
-99-03-31 A bug in shcomp for compilation of unary operators with [[...]]
- has been fixed.
-99-03-31 A bug in which the value of $? was changed when executing
- a keyboard trap has been fixed.
-99-03-31 The handling of SIGCHLD has been changed so that the
- trap is not triggered while executing trap commands
- to avoid recursive trap calls.
-99-03-31 A bug in which a local variable in a function declared readonly
- would generated an error when the function went out of
- scope has been fixed.
-99-03-31 A bug in which \<new_line> entered from the keyboard
- with the KEYBD trap enabled has been fixed.
-99-03-31 The error message for a misplaced ((, for example print ((3),
- was often garbled and has been fixed.
-99-03-31 A bug in the KEYBD trap in which escape sequences of the form
- <ESC>[#~ were not being handled as a unit has been fixed.
-99-03-31 A bug in which ksh would consider expressions like [[ (a) ]]
- as syntax errors has been fixed.
-99-03-31 A function defined as foo() without a function body
- was not reported as a syntax error.
-99-03-31 A bug in which ksh could run out of file descriptors when
- a stream was repeatedly opened with exec and read from
- has been fixed.
-
-98-04-30 --- Release ksh93g ---
-98-04-30 The pipefail option has been added. With pipefail
- enabled, a pipeline will not complete until all
- commands are complete, and the return value will
- be that of the last command to fail, or zero if
- all complete successfully.
-98-04-30 The name-value pair library uses the cdt library rather
- than the hash library. This change should be transparent
- to applications.
-98-04-30 On the U/WIN version for Window 95 and Windows NT,
- when a directory beginning with a letter followed by
- a colon is given to cd, it is assumed to be an absolute
- directory
-98-04-30 When an executable is found on a given path,
- the appropriate library path variable is prepended
- with a corresponding library directory.
-98-04-30 A bug in which a name reference could be created to
- itself and later cause the shell to get into an infinite
- loop has been fixed.
-98-04-30 A bug in shcomp relating to compound variables was fixed.
-98-04-30 A bug introduced in ksh93e in which leading 0's in -Z
- fields caused the value to be treated as octal for arithmetic
- evaluation has been fixed.
-98-04-30 A bug when a name reference with a shorter name than
- the variable it references was the subject of a compound
- assignment has been fixed.
-98-04-30 A bug which in which assignment to array variables in
- a subshell could effect the parent shell has been
- fixed.
-98-04-30 read name?prompt was putting a 0 byte at the end of the
- prompt on standard error.
-98-04-30 A bug in [[ string1 > string2 ]] when ksh was run with -x
- has been fixed.
-98-04-30 A bug in which the escape character was not processed
- correctly inside {...} when brace expansion is enabled
- has been fixed, for example {\$foo}.
-98-04-30 A bug in line continuation in here-documents has been
- fixed.
-98-04-30 The default base when not specified with typeset -i is
- 10 in accordance with the documentation. Previously,
- the value was determined by the first assignment.
-98-04-30 A parsing bug in which a # preceded alphanumeric
- characters inside a command substitution caused
- a syntax error to be reported has been fixed.
-98-04-30 A bug in which a decimal constant represented as 10#ddd
- where ddd was more than five digits generated a syntax
- error has been fixed.
-98-04-30 A bug in here document expansion in which ${...} expansions
- were split across buffer boundaries has been fixed.
-98-04-30 The sh_fun() function now takes third argument which
- is an argument list for the invoked discipline function
- or built-in.
-98-04-30 A callback function can be installed which will give
- notification of file duplications and file closes.
-98-04-30 When ksh is compiled on systems that do not use fork()
- current option settings where not propagated to sub-shells.
-
-97-06-30 --- Release ksh93f ---
-97-06-30 Hostnames in addition to host addresses can be given in
- /dev/tcp/host/port virtual file names.
-97-06-30 File name completion and expansion now quotes special
- characters in file names from both emacs and vi edit modes.
-97-06-30 An empty for list behave like a for list with null expansions.
- It produces a warning message with sh -n.
-97-06-30 The code has been modified to work with EBCDIC as well as ASCII.
-97-06-30 A bug which would cause the secondary prompt to be
- displayed when a user entered a literal carriage
- return has been fixed.
-97-06-30 A bug which caused ksh read -s name to core dump was
- fixed.
-97-06-30 A bug with the expansion of \} and \] inside double
- quoted strings that also contained variable expansions
- has been fixed
-97-06-30 Changes in the ksh93e point release caused autoload
- functions invoked from within command substitution
- to fail. This has been fixed.
-97-06-30 A bug in the processing of here-documents that could
- prevent variable substitution to occur after $(...) command
- substitution for long here documents has been fixed.
-97-06-30 A bug caused by a race condition that could cause SIGTERM
- to be ignored by a child process has been fixed.
-97-06-30 A bug which prevented the startup of a coprocess immediately
- after killing a running coprocess has been fixed.
-97-06-30 ulimit foobar, where foobar is not an arithmetic
- expression, now gives an error message as it did with ksh88
- instead of setting the file size limit to 0.
-97-06-30 A bug which could cause an interactive shell to terminate when
- the last process of a pipeline was a POSIX function was fixed.
-97-06-30 A bug which could cause command substitution of a shell script
- to core dump has been fixed.
-97-06-30 A security hole was fixed in suid_exec.
-97-06-30 Arithmetic functions such as pow() that take more than
- one argument, did not work if arguments other than the
- first contained parenthesized sub-expression.
-97-06-30 The error message from a script containing an incomplete
- arithmetic expression has been corrected.
-97-06-30 A bug which caused a core dump on some machines when
- the value of a name reference contained a positional
- parameter and the name reference was not defined inside
- a function has been fixed.
-97-06-30 Arithmetic expressions now correctly handle hexadecimal
- constants.
-97-06-30 A bug in which integer variables could be expanded
- with a leading 10# when declared with typeset -i
- multiple times has been corrected.
-97-06-30 A bug in which IFS wasn't correctly restored when
- set within command substitution has been fixed.
-97-06-30 The _ character is now considered as part of a word
- with the M-f and M-b emacs directives as it was in ksh88.
-97-06-30 A bug in brace pattern expansions that caused expressions
- such as {foo\,bar,bam} to expand incorrectly have been fixed.
-
-
-96-07-31 --- Release ksh93e ---
-96-07-31 The math functions, atan2, hypot, fmod, and pow were added.
-96-07-31 When a shared library is loaded, if the function lib_init()
- is defined in the library, it is invoked the first time that
- the library is loaded with builtin -f library.
-96-07-31 The k-shell information abstraction database option, KIA,
- has been revamped.
-96-07-31 Empty command substitutions of the form $() now work.
- whence -v foo now gives the correct result after calling
- builtin -d foo.
-96-07-31 A bug in right to left arithmetic assignment for which
- the arithmetic expression (( y = x = 1.5 )) did not
- yield 1 for y when x was declared typeset -i was fixed.
-96-07-31 printf has been fixed to handle format containing \0
- and/or \0145 correctly. In addition, characters following
- %b in the format string are no longer displayed when
- the operand contains \c.
-96-07-31 A bug in printf that could cause the %E format to
- produce unnormalized results has been fixed.
-96-07-31 A bug which causes some arithmetic expressions to be
- incorrectly evaluated as integer expressions rather
- that floating point has been fixed.
-96-07-31 Functions defined inside a subshell no longer remain
- defined when the subshell completes.
-96-07-31 The error message from sh -c ';echo foo' has been
- corrected.
-96-07-31 The format for umask -S has been changed to agree
- with the specification in the POSIX standard.
-96-07-31 A bug that caused side effects in subscript evaluation
- when tracing was enabled for subscripts using ++ or --
- has been fixed.
-96-07-31 To conform to the Posix standard getopts has been changed
- so that the option char is set to ? when it returns with
- a non-zero exit status.
-96-07-31 The handling of \} inside ${name...} has been fixed so
- that the \ quotes the }.
-96-07-31 A bug that caused the read builtin to resume execution
- after processing a trap has been fixed.
-96-07-31 [[ -s file ]] has been fixed so that if file is open
- by ksh, it is flushed first.
-96-07-31 In some cases attributes and sizes for non exported
- variables weren't being reset before running a script.
-96-07-31 The value of TMOUT was affected by changes make to
- it in a subshell.
-96-07-31 The jobs command did not reflect changes make by
- sending the CONT signal to a command.
-96-07-31 The error message for ksh -o unknown was incorrect.
-96-07-31 Functions invoked as name=value name, did not use
- values from the calling scope when evaluating value.
-96-07-31 A bug in which the shell would reexecute previously
- executed code when a shell script or coprocess was
- run in the background has been fixed.
-96-07-31 A bug in which an empty here-document would leave
- a file descriptor open has been fixed.
-96-07-31 A bug in which $(set -A array ...) would leave a
- side effect has been fixed.
-96-07-31 A discipline function for a global variable defined
- within a function defined with the function keyword,
- incorrectly created a local variable of the same name
- and applied the discipline to it.
-
-95-08-28 --- Release ksh93d ---
-95-08-28 The \ character was not handled correctly in replacement
- patterns with ${x/pattern/replace}.
-95-08-28 A bug with read in which the line did not end with
- a new-line has been fixed.
-95-08-28 A bug in file name generation which sometimes
- appended a . for filenames that ended in / has
- been fixed.
-95-08-28 If a process is waited for after a status has
- been returned by a previous wait, wait now
- returns 127.
-95-08-28 A bug with hist (fc) -e which prevented a command
- to re-executed after it had been edited has been fixed.
-95-08-28 A bug which prevented quoting from removing the meaning
- of unary test operators has been fixed.
-95-08-28 A bug with typeahead and KEYBOARD traps with the
- MULTIBYTE option set has been fixed.
-95-08-28 Builtin functions can take a third argument which is
- a void*.
-95-08-28 The nv_scan() function can restrict the scope of a walk
- to the top scope.
-
-95-04-31 --- Release ksh93c ---
-95-04-31 The expansion of "$@" was incorrect when $1 was the null
- string.
-95-04-31 A bug which could incorrectly report a syntax error in
- a backquoted expression when a $ was preceded by \\
- has been fixed.
-95-04-31 A bug which prevented the shell from exiting after
- reporting an error when failing to open a script
- has been fixed.
-95-04-31 A bug that could lead to memory corruption when a
- large here document that required parameter or command
- substitution was expanded has been fixed.
-95-04-31 A bug that could cause a core dump on some systems
- after ksh detected an error when reading a function
- has been fixed.
-95-04-31 A bug which could cause a coprocess to hang when
- reading from a process that has terminated has been fixed.
-95-04-31 A bug which caused a script to terminate when set -e
- was on and the first command of and && or || list
- failed has been fixed.
-95-04-31 A bug with here documents inside $(...) when the delimiter
- word is an identifier has been fixed.
-95-04-31 A bug which caused $0 to display the wrong value when
- a script was invoked as an argument to the . command
- and the eval command has been fixed.
-95-04-31 A bug that could cause the built-in sleep to hang
- has been fixed.
-95-04-31 A bug introduces in 12/28/93b which caused the backslash
- to be removed when it was followed by digit inside double
- quotes in some instances has been fixed.
-95-04-31 A bug which could cause a core dump if ksh was invoked with
- standard input closed has been fixed.
-95-04-31 A bug which could cause a core dump if typeset -A was
- specified for an existing variable has been fixed.
-95-04-31 Variables that were unset but had attributes such as readonly
- and export were not listed with readonly, export and typeset.
-95-04-31 Several problems with signals have been fixed.
-95-04-31 A bug which prevented ulimit -t from working has been fixed.
- Also, a bug in which failed ulimits could cause a core dump
- has also been fixed.
-95-04-31 A bug in expansion of the form ${name/#pattern/string} and
- ${name/%pattern/string} has been fixed.
-95-04-31 A bug which caused read -r on a line that contained only
- blanks to get a non-null value has been fixed.
-95-04-31 A bug introduced in the 'a' point release in which
- ${x='\\'} expanded to \ when x was unset has been fixed.
-95-04-31 A bug which prevented a trap on EXIT from being executed
- when the last command in a script was a function invocation
- has been fixed.
-95-04-31 A bug which caused an interactive shell ignore input when
- standard error was redirected to a file with exec,
- and then restored with exec 2>&1 has been fixed.
-95-04-31 An interactive shell turns on monitor mode even when
- standard error has been redirected to a file.
-95-04-31 A bug which could cause standard input to be incorrectly
- positioned for the last command of a script has been fixed.
-95-04-31 A bug in the edit modes which allowed walking back in
- the history file for more than HISTSIZE commands has
- been fixed.
-95-04-31 A bug which could cause a core dump if variable TMPDIR was
- changed between two command substitutions has been fixed.
-95-04-31. A bug which prevented a trap on EXIT from being cleared
- has been fixed.
-95-04-31 A bug fixed for the v directive in vi MULTIBYTE has been
- fixed.
-95-04-31 Code to for IFS handling of multibyte characters has
- been added.
-95-04-31 The displaying of multibyte strings in export, readonly,
- typeset, and execution traces has been fixed.
-95-04-31 Variables inside functions are now statically scoped.
- The previous behavior was never documented.
-95-04-31 Variables inside functions are now statically scoped.
- The previous behavior was never documented.
-95-04-31 A few changes have been made to the name-value library
- that affect built-ins that use disciplines. The
- changes allow disciplines to be shared by variables
- and should make it possible to add new disciplines
- without recompilation.
-95-04-31 The name-value library interface has undergone significant
- change for this revision. See the new nval.3 man page.
-
-94-12-31 --- Release ksh93b ---
-94-12-31 Variables inside functions are now statically scoped.
- The previous behavior was never documented.
-94-12-31 If IFS contains two consecutive identical characters belonging
- to the [:space:] class, then this character is treated as
- a non-space delimiter so that each instance will delimit
- a field. For example, IFS=$'\t\t' will cause two consecutive
- tabs to delimit a null field.
-94-12-31 The getopts command has a -a name option that specifies a
- name that will be used for usage messages.
-94-12-31 A bug which caused unset RANDOM to dump core has been
- fixed.
-94-12-31 A bug which prevented return for terminating a profile
- or ENV file has been fixed.
-94-12-31 A bug which prevented standard input from being
- directed to /dev/null for background jobs when
- monitor mode was turned off has been fixed.
-94-12-31 Statements of the form typeset -options var[expr]=value
- did not perform substitutions on expr as expected.
-94-12-31 A bug which prevented the shell from sending a HUP
- signal to some background jobs that were not disowned
- has been fixed.
-94-12-31 A bug which allowed a script to trap signals that are
- ignored at the time that the shell was invoked by exec
- has been fixed.
-94-12-31 A bug which could cause a core dump when a discipline
- function was unset within a discipline was fixed.
-94-12-31 The typeset builtin now accepts a first argument of
- + or - for compatibility with ksh88.
-94-12-31 For compatibility with ksh88, the results of expansions
- of command arguments will treat the extended character
- match characters ()|& as ordinary characters.
-94-12-31 A bug which caused read to fail on a file that was
- open for read/write with <> when the first operation
- was print or printf has been fixed.
-94-12-31 When a job is suspended, it is put on the top of
- the job list as required by the POSIX standard.
-94-12-31 The value of OPTARG when an option that required
- an argument but didn't have one was incorrect in the
- case the the option string began with a :.
-94-12-31 A bug which caused the terminal to get into a bad
- state with some KEYBD traps in vi-mode has been fixed.
-94-12-31 A bug which caused an invalid trap to cause a script
- to terminate, rather than just return an error, has
- been fixed.
-94-12-31 Backreferencing sub-expressions in patterns and replacement
- strings now works.
-94-12-31 A bug in chmod which caused the -R option to fail has
- been fixed.
-94-12-31 More signal names have been added for Solaris
-
-94-06-30 --- Release ksh93a ---
-94-06-30 An expansion bug which causes portions of a word after
- a $((...)) expansion that contains a nested $var expansion
- to be lost has been fixed.
-94-06-30 A bug that caused a core dump when a script that did not
- have PWD set and did a cd inside command substitution
- has been fixed.
-94-06-30 A bug which caused a core dump on some machines when
- the LANG variable was assigned to has been fixed.
-94-06-30 A bug which incorrectly handled set disciplines that
- performed arithmetic evaluation when the discipline
- was called from the arithmetic evaluator has been fixed.
-94-06-30 A bug caused by an EXIT trap inside a function that
- was executed in a subshell was fixed.
-94-06-30 If foo is a function, and not a program, then command foo
- now reports that foo isn't found rather than invoking foo.
-94-06-30 The previous version incorrectly listed -A as an
- invocation option. The -A option is only for set.
-94-06-30 A bug was fixed which caused ksh to loop when execution trace
- was enabled and the PS4 prompt required command substitution.
-94-06-30 A bug which could cause the job control switch character
- to be disabled when a script that enabled monitor mode
- terminated was fixed.
-94-06-30 A bug in the macro expansion global replacement operator //,
- when the pattern began with a [ or +( has been fixed.
-94-06-30 A bug which prevented ~ expansion from occurring when
- it was terminated with a colon inside an assignment
- has been fixed.
-94-06-30 A bug in the dot command which prevented autoload functions
- from working has been fixed.
-94-06-30 A bug which caused a variable to be unset if the
- its value were expanded inside a set discipline has
- been fixed.
-94-06-30 Whence -a now longer reports that a defined function
- is undefined.
-94-06-30 A bug on some systems in which $0 would be incorrect
- in scripts invoked by name has been fixed.
-94-06-30 Here documents with an empty body now work.
-94-06-30 A bug which disabled argument passing and resetting
- of options for a script invoked by name inside a
- function has been fixed.
-94-06-30 A bug in which an EXIT trap set the caller of a function
- would be executed if a command called inside a function
- was not found has been fixed.
-94-06-30 A bug which allowed a script to trap signals that are
- ignored at the time that the shell was invoked has
- been fixed.
-94-06-30 A bug which caused 2<&1- when applied to a shell built-in
- to leave standard input closed has been fixed.
-94-06-30 A bug which caused the shell to incorrectly parse
- $() command substitutions with nested case statements
- has been fixed.
-
diff --git a/usr/src/lib/libshell/common/TYPES b/usr/src/lib/libshell/common/TYPES
deleted file mode 100644
index 6eb6f41b5e..0000000000
--- a/usr/src/lib/libshell/common/TYPES
+++ /dev/null
@@ -1,182 +0,0 @@
-
-The ability for users to define types has been added to ksh93t.
-Here is a quick summary of how types are defined and used in ksh93t.
-This is still a work in progress so some changes and additions
-are likely.
-
-A type can be defined either by a shared library or by using the new
-typeset -T option to the shell. The method for defining types via
-a shared library is not described here. However, the source file
-bltins/enum.c is an example of a builtin that creates enumeration types.
-
-By convention, typenames begin with a capitol letter and end in _t.
-To define a type, use
- typeset -T Type_t=(
- definition
- )
-where definition contains assignment commands, declaration commands,
-and function definitions. A declaration command (for example typeset,
-readonly, and export), is a built-in that differs from other builtins in
-that tilde substitution is performed on arguments after an =, assignments
-do not have to precede the command name, and field splitting and pathname
-expansion is not performed on the arguments.
-For example,
- typeset -T Pt_t=(
- float -h 'length in inches' x=1
- float -h 'width in inches' y=0
- integer -S count=0
- len()
- {
- print -r $((sqrt(_.x*_.x + _.y*_.y)))
- }
- set()
- {
- (( _.count++))
- }
- )
-
-defines a type Pt_t that has three variables x, y, and count defined as well
-as the discipline functions len and set. The variable x has an initial value
-of 1 and the variable y has an initial value of 0. The new -h option argument,
-is used for documentations purposes as described later and is ignored outside
-of a type definition.
-
-
-The variable count has the new -S attribute which means that it is shared
-between all instances of the type. The -S option to typeset is ignored
-outside of a type definition. Note the variable named _ that is used inside
-the function definition for len and set. It will be a reference to the
-instance of Pt_t that invoked the function. The functions len and set
-could also have been defined with function len and function set, but
-since there are no local variables, the len() and set() form are more
-efficient since they don't need to set up a context for local variables
-and for saving and restoring traps.
-
-If the discipline function named create is defined it will be
-invoked when creating each instance for that type. A function named
-create cannot be defined by any instance.
-
-When a type is defined, a declaration built-in command by this name
-is added to ksh. As with other shell builtins, you can get the man page
-for this newly added command by invoking Pt_t --man. The information from
-the -h options will be embedded in this man page. Any functions that
-use getopts to process arguments will be cross referenced on the generated
-man page.
-
-Since Pt_t is now a declaration command it can be used in the definition
-of other types, for example
- typeset -T Rect_t=( Pt_t ur ll)
-
-Because a type definition is a command, it can be loaded on first reference
-by putting the definition into a file that is found on FPATH.
-Thus, if this definition is in a file named Pt_t on FPATH, then
-a program can create instances of Pt_t without first including
-the definition.
-
-A type definition is readonly and cannot be unset. Unsetting non-shared
-elements of a type restores them to their default value. Unsetting a
-shared element has no effect.
-
-The Pt_t command is used to create an instance of Pt_t.
- Pt_t p1
-creates an instance named p1 with the initial value for p1.x set to 1
-and the initial value of p1.y set to 0.
- Pt_t p2=(x=3 y=4)
-creates an instance with the specified initial values. The len function
-gives the distance of the point to the origin. Thus, p1.len will output
-1 and p2.len will output 5.
-
-ksh93t also introduces a more efficient command substitution mechanism.
-Instead of $(command), the new command substitution ${ command;}
-can be used. Unlike (and ) which are always special, the { and } are
-reserved words and require the space after { and a newline or ; before }.
-Unlike $(), the ${ ;} command substitution executes the command in
-the current shell context saving the need to save and restore
-changes, therefore also allowing side effects.
-
-When trying to expand an element of a type, if the element does not exist,
-ksh will look for a discipline function with that name and treat this as if
-it were the ${ ;} command substitution. Thus, ${p1.len} is equivalent to
-${ p1.len;} and within an arithmetic expression, p1.len will be expanded
-via the new command substitution method.
-
-The type of any variable can be obtained from the new prefix
-operator @. Thus, ${@p1} will output Pt_t.
-
-By default, each instance inherits all the discipline functions defined
-by the type definition other than create. However, each instance can define
-a function by the same name that will override this definition.
-However, only discipline functions with the same name as those defined
-by the type or the standard get, set, append, and unset disciplines
-can be defined by each instance.
-
-Each instance of the type Pt_t behaves like a compound variable except
-that only the variables defined by the type can be referenced or set.
-Thus, p2.x=9 is valid, but p2.z=9 is not. Unless a set discipline function
-does otherwise, the value of $p1 will be expanded to the form of a compound
-variable that can be used for reinput into ksh.
-
-If the variables var1 and var2 are of the same type, then the assignment
- var2=var1
-will create a copy of the variable var1 into var2. This is equivalent to
- eval var2="$var1"
-but is faster since the variable does not need to get expanded or reparsed.
-
-The type Pt_t can be referenced as if it were a variable using the name
-.sh.type.Pt_t. To change the default point location for subsequent
-instances of Pt_t, you can do
- .sh.type.Pt_t=(x=5 y=12)
-so that
- Pt_t p3
- p3.len
-would be 13.
-
-Types can be defined for simple variables as well as for compound
-objects such as Pt_t. In this case, the variable named . inside
-the definition refers to the real value for the variable. For example,
-the type definition
- typeset -T Time_t=(
- integer .=0
- _='%H:%M:%S'
- get()
- {
- .sh.value=$(printf "%(${_._})T" "#$((_))" )
- }
- set()
- {
- .sh.value=$(printf "%(%#)T" "${.sh.value}")
-
- }
- )
-
-The sub-variable name _ is reserved for data used by discipline functions
-and will not be included with data written with the %B option to printf.
-In this case it is used to specify a date format.
-
-In this case
- Time_t t1 t2=now
-will define t1 as the time at the beginning of the epoch and t2
-as the current time. Unlike the previous case, $t2 will output
-the current time in the date format specified by the value t2._.
-However, the value of ${t2.} will expand the instance to a form
-that can be used as input to the shell.
-
-Finally, types can be derived from an existing type. If the first
-element in a type definition is named _, then the new type
-consists of all the elements and discipline functions from the
-type of _ extended by elements and discipline functions defined
-by new type definition. For example,
-
- typeset -T Pq_t=(
- Pt_t _
- float z=0.
- len()
- {
- print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z)))
- }
- )
-
-defines a new type Pq_t which is based on Pq_t and contains an additional
-field z and a different len discipline function. It is also possible
-to create a new type Pt_t based on the original Pt_t. In this case
-the original Pt_t is no longer accessible.
diff --git a/usr/src/lib/libshell/misc/images/callouts/1.png b/usr/src/lib/libshell/misc/images/callouts/1.png
deleted file mode 100644
index 608fad3596..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/1.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/10.png b/usr/src/lib/libshell/misc/images/callouts/10.png
deleted file mode 100644
index 39e55197cf..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/10.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/2.png b/usr/src/lib/libshell/misc/images/callouts/2.png
deleted file mode 100644
index 5444738841..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/2.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/3.png b/usr/src/lib/libshell/misc/images/callouts/3.png
deleted file mode 100644
index 64b87c7151..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/3.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/4.png b/usr/src/lib/libshell/misc/images/callouts/4.png
deleted file mode 100644
index c308193ac4..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/4.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/5.png b/usr/src/lib/libshell/misc/images/callouts/5.png
deleted file mode 100644
index 24799f0a43..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/5.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/6.png b/usr/src/lib/libshell/misc/images/callouts/6.png
deleted file mode 100644
index 8919a670cd..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/6.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/7.png b/usr/src/lib/libshell/misc/images/callouts/7.png
deleted file mode 100644
index e30e8a70cb..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/7.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/8.png b/usr/src/lib/libshell/misc/images/callouts/8.png
deleted file mode 100644
index 3e35c8827c..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/8.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/callouts/9.png b/usr/src/lib/libshell/misc/images/callouts/9.png
deleted file mode 100644
index ed2f14b4eb..0000000000
--- a/usr/src/lib/libshell/misc/images/callouts/9.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_bourne.png b/usr/src/lib/libshell/misc/images/tag_bourne.png
deleted file mode 100644
index f1f78e3a25..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_bourne.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_i18n.png b/usr/src/lib/libshell/misc/images/tag_i18n.png
deleted file mode 100644
index 559929df2a..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_i18n.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_ksh.png b/usr/src/lib/libshell/misc/images/tag_ksh.png
deleted file mode 100644
index b33d5a7aa1..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_ksh.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_ksh88.png b/usr/src/lib/libshell/misc/images/tag_ksh88.png
deleted file mode 100644
index d36dc0f5f5..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_ksh88.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_ksh93.png b/usr/src/lib/libshell/misc/images/tag_ksh93.png
deleted file mode 100644
index 357ee3c50a..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_ksh93.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_l10n.png b/usr/src/lib/libshell/misc/images/tag_l10n.png
deleted file mode 100644
index be89f7a163..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_l10n.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/images/tag_perf.png b/usr/src/lib/libshell/misc/images/tag_perf.png
deleted file mode 100644
index fcb2960852..0000000000
--- a/usr/src/lib/libshell/misc/images/tag_perf.png
+++ /dev/null
Binary files differ
diff --git a/usr/src/lib/libshell/misc/shell_styleguide.docbook b/usr/src/lib/libshell/misc/shell_styleguide.docbook
deleted file mode 100644
index 0376912d1f..0000000000
--- a/usr/src/lib/libshell/misc/shell_styleguide.docbook
+++ /dev/null
@@ -1,1464 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN" "http://www.oasis-open.org/docbook/xml/5.0b5/dtd/docbook.dtd" [
- <!ENTITY tag_bourneonly '<inlinemediaobject><imageobject><imagedata fileref="images/tag_bourne.png"></imagedata></imageobject><textobject><phrase>[Bourne]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_kshonly '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh.png"></imagedata></imageobject><textobject><phrase>[ksh]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_ksh88only '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh88.png"></imagedata></imageobject><textobject><phrase>[ksh88]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_ksh93only '<inlinemediaobject><imageobject><imagedata fileref="images/tag_ksh93.png"></imagedata></imageobject><textobject><phrase>[ksh93]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_performance '<inlinemediaobject><imageobject><imagedata fileref="images/tag_perf.png"></imagedata></imageobject><textobject><phrase>[perf]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_i18n '<inlinemediaobject><imageobject><imagedata fileref="images/tag_i18n.png"></imagedata></imageobject><textobject><phrase>[i18n]</phrase></textobject></inlinemediaobject> '>
- <!ENTITY tag_l10n '<inlinemediaobject><imageobject><imagedata fileref="images/tag_l10n.png"></imagedata></imageobject><textobject><phrase>[l10n]</phrase></textobject></inlinemediaobject> '>
-]>
-<!--
-
- CDDL HEADER START
-
- The contents of this file are subject to the terms of the
- Common Development and Distribution License (the "License").
- You may not use this file except in compliance with the License.
-
- You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- or http://www.opensolaris.org/os/licensing.
- See the License for the specific language governing permissions
- and limitations under the License.
-
- When distributing Covered Code, include this CDDL HEADER in each
- file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- If applicable, add the following below this CDDL HEADER, with the
- fields enclosed by brackets "[]" replaced with your own identifying
- information: Portions Copyright [yyyy] [name of copyright owner]
-
- CDDL HEADER END
-
--->
-
-<!--
-
- Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- Use is subject to license terms.
-
--->
-
-<!-- tag images were created like this:
-$ (text="perf" ;
- pbmtext -nomargins -lspace 0 -builtin fixed "${text}" |
- pbmtopgm 1 1 |
- pgmtoppm 1.0,1.0,1.0-0,0,0 /dev/stdin |
- ppmtogif |
- giftopnm |
- pnmtopng >"tag_${text}.png")
--->
-
-<!-- compile with:
-xsltproc &minus;&minus;stringparam generate.section.toc.level 0 \
- &minus;&minus;stringparam toc.max.depth 3 \
- &minus;&minus;stringparam toc.section.depth 12 \
- &minus;&minus;xinclude -o opensolaris_shell_styleguide.html /usr/share/sgml/docbook/docbook-xsl-stylesheets-1.69.1/html/docbook.xsl opensolaris_shell_styleguide.docbook
--->
-
-<article
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns="http://docbook.org/ns/docbook"
- xml:lang="en">
- <!-- xmlns:xi="http://www.w3.org/2001/XInclude" -->
-
- <info>
- <title><emphasis>[DRAFT]</emphasis> Bourne/Korn Shell Coding Conventions</title>
-
- <!-- subtitle abuse -->
- <subtitle>
- This page is currently work-in-progress until it is approved by the OS/Net community. Please send any comments to
- <email>shell-discuss@opensolaris.org</email>.
- </subtitle>
-
-
- <authorgroup>
-<!--
- <author><personname>David G. Korn</personname><email>dgk@research.att.com</email></author>
- <author><personname>Roland Mainz</personname><email>roland.mainz@nrubsig.org</email></author>
- <author><personname>Mike Shapiro</personname><email>mike.shapiro@sun.com</email></author>
--->
- <author><orgname>OpenSolaris.org</orgname></author>
- </authorgroup>
- </info>
-
-<section xml:id="intro">
- <title>Intro</title>
- <para>This document describes the shell coding style used for all the SMF script changes integrated into (Open)Solaris.</para>
- <para>All new SMF shell code should conform to this coding standard, which is intended to match our existing C coding standard.</para>
- <para>When in doubt, think "what would be the C-Style equivalent ?" and "What does the POSIX (shell) standard say ?"</para>
-</section><!-- end of intro -->
-
-
-<section xml:id="rules">
- <title>Rules</title>
-
-
-
- <section xml:id="general">
- <title>General</title>
-
- <section xml:id="basic_format">
- <title>Basic Format</title>
- <para>Similar to <literal>cstyle</literal>, the basic format is that all
- lines are indented by TABs or eight spaces, and continuation lines (which
- in the shell end with "\") are indented by an equivalent number of TABs
- and then an additional four spaces, e.g.
-<programlisting>
-cp foo bar
-cp some_realllllllllllllllly_realllllllllllllly_long_path \
- to_another_really_long_path
-</programlisting>
- </para>
- <para>The encoding used for the shell scripts is either <literal>ASCII</literal>
- or <literal>UTF-8</literal>, alternative encodings are only allowed when the
- application requires this.</para>
- </section>
-
-
- <section xml:id="commenting">
- <title>Commenting</title>
- <para>Shell comments are preceded by the '<literal>#</literal>' character. Place
- single-line comments in the right-hand margin. Use an extra '<literal>#</literal>'
- above and below the comment in the case of multi-line comments:
-<programlisting>
-cp foo bar # Copy foo to bar
-
-#
-# Modify the permissions on bar. We need to set them to root/sys
-# in order to match the package prototype.
-#
-chown root bar
-chgrp sys bar
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="interpreter_magic">
- <title>Interpreter magic</title>
- <para>The proper interpreter magic for your shell script should be one of these:
-<programlisting>
-#!/bin/sh Standard Bourne shell script
-#!/bin/ksh -p Standard Korn shell 88 script. You should always write ksh
- scripts with -p so that ${ENV} (if set by the user) is not
- sourced into your script by the shell.
-#!/bin/ksh93 Standard Korn shell 93 script (-p is not needed since ${ENV} is
- only used for interactive shell sessions).
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="harden_your_script_against_unexpected_input">
- <title>Harden the script against unexpected (user) input</title>
- <para>Harden your script against unexpected (user) input, including
- command line options, filenames with blanks (or other special
- characters) in the name, or file input</para>
- </section>
-
-
- <section xml:id="use_builtin_commands">
- <title>&tag_kshonly;&tag_performance;Use builtin commands if the shell provides them</title>
- <para>
- Use builtin commands if the shell provides them. For example ksh93s+
- (ksh93, version 's+') delivered with Solaris (as defined by PSARC 2006/550)
- supports the following builtins:
- <simplelist type="inline">
- <member>basename</member>
- <member>cat</member>
- <member>chgrp</member>
- <member>chmod</member>
- <member>chown</member>
- <member>cmp</member>
- <member>comm</member>
- <member>cp</member>
- <member>cut</member>
- <member>date</member>
- <member>dirname</member>
- <member>expr</member>
- <member>fds</member>
- <member>fmt</member>
- <member>fold</member>
- <member>getconf</member>
- <member>head</member>
- <member>id</member>
- <member>join</member>
- <member>ln</member>
- <member>logname</member>
- <member>mkdir</member>
- <member>mkfifo</member>
- <member>mv</member>
- <member>paste</member>
- <member>pathchk</member>
- <member>rev</member>
- <member>rm</member>
- <member>rmdir</member>
- <member>stty</member>
- <member>tail</member>
- <member>tee</member>
- <member>tty</member>
- <member>uname</member>
- <member>uniq</member>
- <member>wc</member>
- <member>sync</member>
- </simplelist>
- Those builtins can be enabled via <literal>$ builtin name_of_builtin #</literal> in shell
- scripts (note that ksh93 builtins implement exact POSIX behaviour - some
- commands in Solaris <filename>/usr/bin/</filename> directory implement pre-POSIX behaviour.
- Add <literal>/usr/xpg6/bin/:/usr/xpg4/bin</literal> before
- <filename>/usr/bin/</filename> in <envar>${PATH}</envar> to test whether your script works with
- the XPG6/POSIX versions)
- </para>
- </section>
-
-
- <section xml:id="use_blocks_not_subshells">
- <title>&tag_performance;Use blocks and not subshells if possible</title>
- <para>Use blocks and not subshells if possible, e.g. use
- <literal>$ { print "foo" ; print "bar" ; }</literal> instead of
- <literal>$ (print "foo" ; print "bar") #</literal> - blocks are
- faster since they do not require to save the subshell context (ksh93) or
- trigger a shell child process (Bourne shell, bash, ksh88 etc.)
- </para>
- </section>
-
-
- <section xml:id="use_long_options_for_set_builtin">
- <title>&tag_kshonly; use long options for "<literal>set</literal>"</title>
- <para>use long options for "<literal>set</literal>", for example instead of <literal>$ set -x #</literal>
- use <literal>$ set -o xtrace #</literal> to make the code more readable.</para>
- </section>
-
-
- <section xml:id="use_posix_command_substitutions_syntax">
- <title>&tag_kshonly; Use <literal>$(...)</literal> instead of <literal>`...`</literal> command substitutions</title>
- <para>Use <literal>$(...)</literal> instead of <literal>`...`</literal> - <literal>`...`</literal>
- is an obsolete construct in ksh+POSIX sh scripts and <literal>$(...)</literal>.is a cleaner design,
- requires no escaping rules, allows easy nesting etc.</para>
-
- <note><title>&tag_ksh93only; <literal>${ ...;}</literal>-style command substitutions</title>
- <para>ksh93 has support for an alternative version of command substitutions with the
- syntax <literal>${ ...;}</literal> which do not run in a subshell.
- </para></note>
- </section>
-
-
- <section xml:id="put_command_substitution_result_in_quotes">
- <title>&tag_kshonly; Always put the result of a <literal>$(...)</literal> or
- <literal>$( ...;)</literal> command substitution in quotes</title>
- <para>Always put the result of <literal>$( ... )</literal> or <literal>$( ...;)</literal> in
- quotes (e.g. <literal>foo="$( ... )"</literal> or <literal>foo="$( ...;)"</literal>) unless
- there is a very good reason for not doing it</para>
- </section>
-
-
- <section xml:id="always_set_path">
- <title>Scripts should always set their <envar>PATH</envar></title>
- <para>Scripts should always set their <envar>PATH</envar> to make sure they do not use
- alternative commands by accident (unless the value of <envar>PATH</envar> is well-known
- and guaranteed to be set by the caller)</para>
- </section>
-
-
- <section xml:id="make_sure_commands_are_available">
- <title>Make sure that commands from other packages/applications are really installed on the machine</title>
- <para>Scripts should make sure that commands in optional packages are really
- there, e.g. add a "precheck" block in scipts to avoid later failure when
- doing the main job</para>
- </section>
-
-
- <section xml:id="check_usage_of_boolean_variables">
- <title>Check how boolean values are used/implemented in your application</title>
- <para>Check how boolean values are used in your application.</para>
- <para>For example:
-<programlisting>
-mybool=0
-# do something
-if [ $mybool -eq 1 ] ; then do_something_1 ; fi
-</programlisting>
-could be rewritten like this:
-<programlisting>
-mybool=false # (valid values are "true" or "false", pointing
-# to the builtin equivalents of /bin/true or /bin/false)
-# do something
-if ${mybool} ; then do_something_1 ; fi
-</programlisting>
-or
-<programlisting>
-integer mybool=0 # values are 0 or 1
-# do something
-if (( mybool==1 )) ; then do_something_1 ; fi
-</programlisting>
- </para>
- </section>
-
- <section xml:id="shell_uses_characters_not_bytes">
- <title>&tag_i18n;The shell always operates on <emphasis>characters</emphasis> not bytes</title>
- <para>Shell scripts operate on characters and <emphasis>not</emphasis> bytes.
- Some locales use multiple bytes (called "multibyte locales") to represent one character</para>
-
- <note><para>ksh93 has support for binary variables which explicitly
- operate on bytes, not characters. This is the <emphasis>only</emphasis> allowed
- exception.</para></note>
- </section>
-
-
- <section xml:id="multibyte_locale_input">
- <title>&tag_i18n;Multibyte locales and input</title>
- <para>Think about whether your application has to handle file names or
- variables in multibyte locales and make sure all commands used in your
- script can handle such characters (e.g. lots of commands in Solaris's
- <filename>/usr/bin/</filename> are <emphasis>not</emphasis> able to handle such values - either use ksh93
- builtin constructs (which are guaranteed to be multibyte-aware) or
- commands from <filename>/usr/xpg4/bin/</filename> and/or <filename>/usr/xpg6/bin</filename>)
- </para>
- </section>
-
-
- <section xml:id="use_external_filters_only_for_large_datasets">
- <title>&tag_performance;Only use external filters like <literal>grep</literal>/<literal>sed</literal>/<literal>awk</literal>/etc.
- if you want to process lots of data with them</title>
- <para>Only use external filters like <literal>grep</literal>/<literal>sed</literal>/<literal>awk</literal>/etc.
- if a significant amount of data is processed by the filter or if
- benchmarking shows that the use of builtin commands is significantly slower
- (otherwise the time and resources needed to start the filter are
- far greater then the amount of data being processed,
- creating a performance problem).</para>
- <para>For example:
-<programlisting>
-if [ "$(echo "$x" | egrep '.*foo.*')" != "" ] ; then
- do_something ;
-done
-</programlisting>
-can be re-written using ksh93 builtin constructs, saving several
-<literal>|fork()|+|exec()|</literal>'s:
-<programlisting>
-if [[ "${x}" == ~(E).*foo.* ]] ; then
- do_something ;
-done
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="use_dashdash_if_first_arg_is_variable">
- <title>If the first operand of a command is a variable, use <literal>--</literal></title>
- <para>If the first operand of a command is a variable, use <literal>--</literal>
- for any command that accepts this as end of argument to
- avoid problems if the variable expands to a value starting with <literal>-</literal>.
- </para>
- <note><para>
- At least
- <simplelist type="inline">
- <member>print</member>
- <member>/usr/bin/fgrep</member><member>/usr/xpg4/bin/fgrep</member>
- <member>/usr/bin/grep</member> <member>/usr/xpg4/bin/grep</member>
- <member>/usr/bin/egrep</member><member>/usr/xpg4/bin/egrep</member>
- </simplelist>
- support <literal>--</literal> as "end of arguments"-terminator.
- </para></note>
- </section>
-
- <section xml:id="use_export">
- <title>&tag_kshonly;&tag_performance;Use <literal>$ export FOOBAR=val #</literal> instead of
- <literal>$ FOOBAR=val ; export FOOBAR #</literal></title>
- <para>Use <literal>$ export FOOBAR=val # instead of $ FOOBAR=val ; export FOOBAR #</literal> -
- this is much faster.</para>
- </section>
-
-
- <section xml:id="use_subshell_around_set_dashdash_usage">
- <title>Use a subshell (e.g. <literal>$ ( mycmd ) #</literal>) around places which use
- <literal>set -- $(mycmd)</literal> and/or <literal>shift</literal></title>
- <para>Use a subshell (e.g. <literal>$ ( mycmd ) #</literal>) around places which use
- <literal>set -- $(mycmd)</literal> and/or <literal>shift</literal> unless the variable
- affected is either a local one or if it's guaranteed that this variable will no longer be used
- (be careful for loadable functions, e.g. ksh/ksh93's <literal>autoload</literal> !!!!)
- </para>
- </section>
-
-
- <section xml:id="be_careful_with_tabs_in_script_code">
- <title>Be careful with using TABS in script code, they are not portable
- between editors or platforms</title>
- <para>Be careful with using TABS in script code, they are not portable
- between editors or platforms.</para>
- <para>If you use ksh93 use <literal>$'\t'</literal> to include TABs in sources, not the TAB character itself.</para>
- </section>
-
-
- <section xml:id="centralise_error_exit">
- <title>If you have multiple points where your application exits with an error
- message create a central function for this purpose</title>
- <para>If you have multiple points where your application exits with an error
- message create a central function for this, e.g.
-<programlisting>
-if [ -z "$tmpdir" ] ; then
- print -u2 "mktemp failed to produce output; aborting."
- exit 1
-fi
-if [ ! -d $tmpdir ] ; then
- print -u2 "mktemp failed to create a directory; aborting."
- exit 1
-fi
-</programlisting>
-should be replaced with
-<programlisting>
-function fatal_error
-{
- print -u2 "${progname}: $*"
- exit 1
-}
-# do something (and save ARGV[0] to variable "progname")
-if [ -z "$tmpdir" ] ; then
- fatal_error "mktemp failed to produce output; aborting."
-fi
-if [ ! -d "$tmpdir" ] ; then
- fatal_error "mktemp failed to create a directory; aborting."
-fi
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="use_set_o_nounset">
- <title>&tag_kshonly; Think about using <literal>$ set -o nounset #</literal> by default</title>
- <para>Think about using <literal>$ set -o nounset #</literal> by default (or at least during the
- script's development phase) to catch errors where variables are used
- when they are not set (yet), e.g.
-<screen>
-$ <userinput>(set -o nounset ; print ${foonotset})</userinput>
-<computeroutput>/bin/ksh93: foonotset: parameter not set</computeroutput>
-</screen>
- </para>
- </section>
-
-
- <section xml:id="avoid_eval_builtin">
- <title>Avoid using <literal>eval</literal> unless absolutely necessary</title>
- <para>Avoid using <literal>eval</literal> unless absolutely necessary. Subtle things
- can happen when a string is passed back through the shell
- parser. You can use name references to avoid uses such as
- <literal>eval $name="$value"</literal>.
- </para>
- </section>
-
-
- <section xml:id="use_concatenation_operator">
- <title>&tag_ksh93only;Use the string/array concatenation operator <literal>+=</literal></title>
- <para>Use <literal>+=</literal> instead of manually adding strings/array elements, e.g.
-<programlisting>
-foo=""
-foo="${foo}a"
-foo="${foo}b"
-foo="${foo}c"
-</programlisting>
-should be replaced with
-<programlisting>
-foo=""
-foo+="a"
-foo+="b"
-foo+="c"
-</programlisting>
- </para>
- </section>
-
- <section xml:id="use_source_not_dot">
- <title>&tag_ksh93only;Use <literal>source</literal> instead of '<literal>.</literal> '(dot)
- to include other shell script fragments</title>
- <para>Use <literal>source</literal> instead of '<literal>.</literal>'
- (dot) to include other shell script fragments - the new form is much
- more readable than the tiny dot and a failure can be caught within the script.</para>
- </section>
-
-
- <section xml:id="use_builtin_localisation_support">
- <title>&tag_ksh93only;&tag_performance;&tag_l10n;Use <literal>$"..."</literal> instead of
- <literal>gettext ... "..."</literal> for strings that need to be localized for different locales</title>
- <para>Use $"..." instead of <literal>gettext ... "..."</literal> for strings that need to be
- localized for different locales. <literal>gettext</literal> will require a
- <literal>fork()+exec()</literal> and
- reads the whole catalog each time it's called, creating a huge overhead for localisation
- (and the <literal>$"..."</literal> is easier to use, e.g. you only have to put a
- <literal>$</literal> in front of the catalog and the string will be localised).
- </para>
- </section>
-
-
- <section xml:id="use_set_o_noglob">
- <title>&tag_kshonly;&tag_performance;Use <literal>set -o noglob</literal> if you do not need to expand files</title>
- <para>If you don't expect to expand files, you can do set <literal>-f</literal>
- (<literal>set -o noglob</literal>) as well. This way the need to use <literal>""</literal> is
- greatly reduced.</para>
- </section>
-
-
- <section xml:id="use_empty_ifs_to_handle_spaces">
- <title>&tag_ksh93only;Use <literal>IFS=</literal> to avoid problems with spaces in filenames</title>
- <para>Unless you want to do word splitting, put <literal>IFS=</literal>
- at the beginning of a command. This way spaces in
- file names won't be a problem. You can do
- <literal>IFS='delims' read -r</literal> line
- to override <envar>IFS</envar> just for the <literal>read</literal> command. However,
- you can't do this for the <literal>set</literal> builtin.</para>
- </section>
-
-
- <section xml:id="set_locale_when_comparing_against_localised_output">
- <title>Set the message locale if you process output of tools which may be localised</title>
- <para>Set the message locale (<envar>LC_MESSAGES</envar>) if you process output of tools which may be localised</para>
- <example><title>Set <envar>LC_MESSAGES</envar> when testing for specific outout of the <filename>/usr/bin/file</filename> utility:</title>
-<programlisting>
-# set french as default message locale
-export LC_MESSAGES=fr_FR.UTF-8
-
-...
-
-# test whether the file "/tmp" has the filetype "directory" or not
-# we set LC_MESSAGES to "C" to ensure the returned message is in english
-if [[ "$(LC_MESSAGES=C file /tmp)" = *directory ]] ; then
- print "is a directory"
-fi
-</programlisting>
- <note><para>The environment variable <envar>LC_ALL</envar> always
- overrides any other <envar>LC_*</envar> environment variables
- (and <envar>LANG</envar>, too),
- including <envar>LC_MESSAGES</envar>.
- if there is the chance that <envar>LC_ALL</envar> may be set
- replace <envar>LC_MESSAGES</envar> with <envar>LC_ALL</envar>
- in the example above.</para></note>
- </example>
- </section>
-
- <section xml:id="cleanup_after_yourself">
- <title>Cleanup after yourself.</title>
- <para>Cleanup after yourself. For example ksh/ksh93 have an <literal>EXIT</literal> trap which
- is very useful for this.
- </para>
- <note><para>
- Note that the <literal>EXIT</literal> trap is executed for a subshell and each subshell
- level can run it's own <literal>EXIT</literal> trap, for example
-<screen>
-$ <userinput>(trap "print bam" EXIT ; (trap "print snap" EXIT ; print "foo"))</userinput>
-<computeroutput>foo
-snap
-bam</computeroutput>
-</screen>
- </para></note>
- </section>
-
- <section xml:id="use_proper_exit_code">
- <title>Use a proper <literal>exit</literal> code</title>
- <para>Explicitly set the exit code of a script, otherwise the exit code
- from the last command executed will be used which may trigger problems
- if the value is unexpected.</para>
- </section>
-
-
- <section xml:id="shell_lint">
- <title>&tag_ksh93only;Use <literal>shcomp -n scriptname.sh /dev/null</literal> to check for common errors</title>
- <para>Use <literal>shcomp -n scriptname.sh /dev/null</literal> to
- check for common problems (such as insecure, depreciated or ambiguous constructs) in shell scripts.</para>
- </section>
- </section><!-- end of general -->
-
-
-
-
-
- <section xml:id="functions">
- <title>Functions</title>
-
- <section xml:id="use_functions">
- <title>Use functions to break up your code</title>
- <para>Use functions to break up your code into smaller, logical blocks.</para>
- </section>
-
- <section xml:id="do_not_reserved_keywords_for_function_names">
- <title>Do not use function names which are reserved keywords in C/C++/JAVA or the POSIX shell standard</title>
- <para>Do not use function names which are reserved keywords (or function names) in C/C++/JAVA or the POSIX shell standard
- (to avoid confusion and/or future changes/updates to the shell language).
- </para>
- </section>
-
- <section xml:id="use_ksh_style_function_syntax">
- <title>&tag_kshonly;&tag_performance;Use ksh-style <literal>function</literal></title>
- <para>It is <emphasis>highly</emphasis> recommended to use ksh style functions
- (<literal>function foo { ... }</literal>) instead
- of Bourne-style functions (<literal>foo() { ... }</literal>) if possible
- (and local variables instead of spamming the global namespace).</para>
-
- <warning><para>
- The difference between old-style Bourne functions and ksh functions is one of the major differences
- between ksh88 and ksh93 - ksh88 allowed variables to be local for Bourne-style functions while ksh93
- conforms to the POSIX standard and will use a function-local scope for variables declared in
- Bourne-style functions.</para>
- <para>Example (note that "<literal>integer</literal>" is an alias for "<literal>typeset -li</literal>"):
-<programlisting>
-# new style function with local variable
-$ ksh93 -c 'integer x=2 ; function foo { integer x=5 ; } ; print "x=$x"
-; foo ; print "x=$x" ;'
-x=2
-x=2
-# old style function with an attempt to create a local variable
-$ ksh93 -c 'integer x=2 ; foo() { integer x=5 ; } ; print "x=$x" ; foo ;
-print "x=$x" ;'
-x=2
-x=5
-</programlisting>
-
- <uri xlink:href="http://www.opensolaris.org/os/project/ksh93-integration/docs/ksh93r/general/compatibility/">usr/src/lib/libshell/common/COMPATIBILITY</uri>
- says about this issue:
-<blockquote><para>
-Functions, defined with name() with ksh-93 are compatible with
-the POSIX standard, not with ksh-88. No local variables are
-permitted, and there is no separate scope. Functions defined
-with the function name syntax, maintain compatibility.
-This also affects function traces.
-</para></blockquote>
-(this issue also affects <filename>/usr/xpg4/bin/sh</filename> in Solaris 10 because it is based on ksh88. This is a bug.).
- </para></warning>
-
- </section>
-
-
- <section xml:id="use_proper_return_code">
- <title>Use a proper <literal>return</literal> code</title>
- <para>Explicitly set the return code of a function - otherwise the exit code
- from the last command executed will be used which may trigger problems
- if the value is unexpected.</para>
- <para>The only allowed exception is if a function uses the shell's <literal>errexit</literal> mode to leave
- a function, subshell or the script if a command returns a non-zero exit code.
- </para>
- </section>
-
- <section xml:id="use_fpath_to_load_common_code">
- <title>&tag_kshonly;Use <envar>FPATH</envar> to load common functions, not <literal>source</literal></title>
- <para>
- Use the ksh <envar>FPATH</envar> (function path) feature to load functions which are shared between scripts
- and not <literal>source</literal> - this allows to load such a function on demand and not all at once.</para>
- </section>
-
- </section><!-- end of functions -->
-
-
-
-
- <section xml:id="if_for_while">
- <title><literal>if</literal>, <literal>for</literal> and <literal>while</literal></title>
-
- <section xml:id="if_for_while_format">
- <title>Format</title>
- <para>To match <literal>cstyle</literal>, the shell token equivalent to the <literal>C</literal>
- "<literal>{</literal>" should appear on the same line, separated by a
- "<literal>;</literal>", as in:
-<programlisting>
-if [ "$x" = "hello" ] ; then
- echo $x
-fi
-
-if [[ "$x" = "hello" ]] ; then
- print $x
-fi
-
-for i in 1 2 3; do
- echo $i
-done
-
-for ((i=0 ; i &lt; 3 ; i++)); do
- print $i
-done
-
-while [ $# -gt 0 ]; do
- echo $1
- shift
-done
-
-while (( $# &gt; 0 )); do
- print $1
- shift
-done
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="test_builtin">
- <title><literal>test</literal> Builtin</title>
- <para>DO NOT use the test builtin. Sorry, executive decision.</para>
- <para>In our Bourne shell, the <literal>test</literal> built-in is the same as the "["
- builtin (if you don't believe me, try "type test" or refer to <filename>usr/src/cmd/sh/msg.c</filename>).</para>
- <para>
- So please do not write:
-<programlisting>
-if test $# -gt 0 ; then
-</programlisting>
-instead use:
-<programlisting>
-if [ $# -gt 0 ] ; then
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="use_ksh_test_syntax">
- <title>&tag_kshonly;&tag_performance;Use "<literal>[[ expr ]]</literal>" instead of "<literal>[ expr ]</literal>"</title>
- <para>Use "<literal>[[ expr ]]</literal>" instead of "<literal>[ expr ]</literal>" if possible
- since it avoids going through the whole pattern expansion/etc. machinery and
- adds additional operators not available in the Bourne shell, such as short-circuit
- <literal>&amp;&amp;</literal> and <literal>||</literal>.
- </para>
- </section>
-
-
- <section xml:id="use_posix_arithmetic_expressions">
- <title>&tag_kshonly; Use "<literal>(( ... ))</literal>" for arithmetic expressions</title>
- <para>Use "<literal>(( ... ))</literal>" instead of "<literal>[ expr ]</literal>"
- or "<literal>[[ expr ]]</literal>" expressions.
- </para>
- <para>
- Example: Replace
-<programlisting>
-i=5
-# do something
-if [ $i -gt 5 ] ; then
-</programlisting>
-with
-<programlisting>
-i=5
-# do something
-if (( i &gt; 5 )) ; then
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="compare_exit_code_using_math">
- <title>&tag_kshonly;&tag_performance;Compare exit code using arithmetic expressions expressions</title>
- <para>Use POSIX arithmetic expressions to test for exit/return codes of commands and functions.
- For example turn
-<programlisting>
-if [ $? -gt 0 ] ; then
-</programlisting>
-into
-<programlisting>
-if (( $? &gt; 0 )) ; then
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="use_builtin_commands_in_loops">
- <title>&tag_bourneonly; Use builtin commands in conditions for <literal>while</literal> endless loops</title>
- <para>Make sure that your shell has a "<literal>true</literal>" builtin (like ksh93) when
- executing endless loops like <literal>$ while true ; do do_something ; done #</literal> -
- otherwise each loop cycle runs a <literal>|fork()|+|exec()|</literal>-cycle to run
- <filename>/bin/true</filename>
- </para>
- </section>
-
-
- <section xml:id="single_line_if_statements">
- <title>Single-line if-statements</title>
- <para>It is permissible to use <literal>&amp;&amp;</literal> and <literal>||</literal> to construct
- shorthand for an "<literal>if</literal>" statement in the case where the if statement has a
- single consequent line:
-<programlisting>
-[ $# -eq 0 ] &amp;&amp; exit 0
-</programlisting>
-instead of the longer:
-<programlisting>
-if [ $# -eq 0 ]; then
- exit 0
-fi
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="exit_status_and_if_for_while">
- <title>Exit Status and <literal>if</literal>/<literal>while</literal> statements</title>
- <para>Recall that "<literal>if</literal>" and "<literal>while</literal>"
- operate on the exit status of the statement
- to be executed. In the shell, zero (0) means true and non-zero means false.
- The exit status of the last command which was executed is available in the $?
- variable. When using "<literal>if</literal>" and "<literal>while</literal>",
- it is typically not necessary to use
- <literal>$?</literal> explicitly, as in:
-<programlisting>
-grep foo /etc/passwd &gt;/dev/null 2>&amp;1
-if [ $? -eq 0 ]; then
- echo "found"
-fi
-</programlisting>
-Instead, you can more concisely write:
-<programlisting>
-if grep foo /etc/passwd &gt;/dev/null 2>&amp;1; then
- echo "found"
-fi
-</programlisting>
-Or, when appropriate:
-<programlisting>
-grep foo /etc/passwd &gt;/dev/null 2>&amp;1 &amp;&amp; echo "found"
-</programlisting>
- </para>
- </section>
-
- </section><!-- end of if/for/while -->
-
-
-
-
-
-
- <section xml:id="variables">
- <title>Variable types, naming and usage</title>
-
- <section xml:id="names_should_be_lowercase">
- <title>Names of local, non-environment, non-constant variables should be lowercase</title>
- <para>Names of variables local to the current script which are not exported to the environment
- should be lowercase while variable names which are exported to the
- environment should be uppercase.</para>
- <para>The only exception are global constants (=global readonly variables,
- e.g. <literal>$ float -r M_PI=3.14159265358979323846 #</literal> (taken from &lt;math.h&gt;))
- which may be allowed to use uppercase names, too.
- </para>
-
- <warning><para>
- Uppercase variable names should be avoided because there is a good chance
- of naming collisions with either special variable names used by the shell
- (e.g. <literal>PWD</literal>, <literal>SECONDS</literal> etc.).
- </para></warning>
- </section>
-
- <section xml:id="do_not_reserved_keywords_for_variable_names">
- <title>Do not use variable names which are reserved keywords/variable names in C/C++/JAVA or the POSIX shell standard</title>
- <para>Do not use variable names which are reserved keywords in C/C++/JAVA or the POSIX shell standard
- (to avoid confusion and/or future changes/updates to the shell language).
- </para>
- <note>
- <para>The Korn Shell and the POSIX shell standard have many more
- reserved variable names than the original Bourne shell. All
- these reserved variable names are spelled uppercase.
- </para>
- </note>
- </section>
-
- <section xml:id="use_brackets_around_long_names">
- <title>Always use <literal>'{'</literal>+<literal>'}'</literal> when using variable
- names longer than one character</title>
- <para>Always use <literal>'{'</literal>+<literal>'}'</literal> when using
- variable names longer than one character unless a simple variable name is
- followed by a blank, <literal>/</literal>, <literal>;</literal>, or <literal>$</literal>
- character (to avoid problems with array,
- compound variables or accidental misinterpretation by users/shell)
-<programlisting>
-print "$foo=info"
-</programlisting>
-should be rewritten to
-<programlisting>
-print "${foo}=info"
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="quote_variables_containing_filenames_or_userinput">
- <title><emphasis>Always</emphasis> put variables into quotes when handling filenames or user input</title>
- <para><emphasis>Always</emphasis> put variables into quotes when handling filenames or user input, even if
- the values are hardcoded or the values appear to be fixed. Otherwise at
- least two things may go wrong:
- <itemizedlist>
- <listitem><para>a malicious user may be able to exploit a script's inner working to
- infect his/her own code</para></listitem>
- <listitem><para>a script may (fatally) misbehave for unexpected input (e.g. file names
- with blanks and/or special symbols which are interpreted by the shell)</para></listitem>
- </itemizedlist>
- </para>
-
- <note><para>
- As alternative a script may set <literal>IFS='' ; set -o noglob</literal> to turn off the
- interpretation of any field seperators and the pattern globbing.
- </para></note>
- </section>
-
-
-
- <section xml:id="use_typed_variables">
- <title>&tag_kshonly;&tag_performance;Use typed variables if possible.</title>
- <para>For example the following is very
- inefficient since it transforms the integer values to strings and back
- several times:
-<programlisting>
-a=0
-b=1
-c=2
-# more code
-if [ $a -lt 5 -o $b -gt c ] ; then do_something ; fi
-</programlisting>
-This could be rewritten using ksh constructs:
-<programlisting>
-integer a=0
-integer b=1
-integer c=2
-# more code
-if (( a &lt; 5 || b &gt; c )) ; then do_something ; fi
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="store_lists_in_arrays">
- <title>&tag_ksh93only; Store lists in arrays or associative arrays</title>
- <para>Store lists in arrays or associative arrays - this is usually easier
- to manage.</para>
- <para>
- For example:
-<programlisting>
-x="
-/etc/foo
-/etc/bar
-/etc/baz
-"
-echo $x
-</programlisting>
-can be replaced with
-<programlisting>
-typeset -a mylist
-mylist[0]="/etc/foo"
-mylist[1]="/etc/bar"
-mylist[2]="/etc/baz"
-print "${mylist[@]}"
-</programlisting>
-or (ksh93-style append entries to a normal (non-associative) array)
-<programlisting>
-typeset -a mylist
-mylist+=( "/etc/foo" )
-mylist+=( "/etc/bar" )
-mylist+=( "/etc/baz" )
-print "${mylist[@]}"
-</programlisting>
- </para>
- <note>
- <title>Difference between expanding arrays with mylist[@] and mylist[*] subscript operators</title>
- <para>
- Arrays may be expanded using two similar subscript operators, @ and *. These subscripts
- differ only when the variable expansion appears within double quotes. If the variable expansion
- is between double-quotes, "${mylist[*]}" expands to a single string with the value of each array
- member separated by the first character of the <envar>IFS</envar> variable, and "${mylist[@]}"
- expands each element of name to a separate string.
- </para>
- <example><title>Difference between [@] and [*] when expanding arrays</title>
-<programlisting>
-typeset -a mylist
-mylist+=( "/etc/foo" )
-mylist+=( "/etc/bar" )
-mylist+=( "/etc/baz" )
-IFS=","
-printf "mylist[*]={ 0=|%s| 1=|%s| 2=|%s| 3=|%s| }\n" "${mylist[*]}"
-printf "mylist[@]={ 0=|%s| 1=|%s| 2=|%s| 3=|%s| }\n" "${mylist[@]}"
-</programlisting>
-<para>will print:</para>
-<screen>
-<computeroutput>mylist[*]={ 0=|/etc/foo,/etc/bar,/etc/baz| 1=|| 2=|| 3=|| }
-mylist[@]={ 0=|/etc/foo| 1=|/etc/bar| 2=|/etc/baz| 3=|| }
-</computeroutput>
-</screen>
- </example>
- </note>
- </section>
-
-
- <section xml:id="use_compound_variables_or_lists_for_grouping">
- <title>&tag_ksh93only; Use compound variables or associative arrays to group similar variables together</title>
- <para>Use compound variables or associative arrays to group similar variables together.</para>
- <para>
- For example:
-<programlisting>
-box_width=56
-box_height=10
-box_depth=19
-echo "${box_width} ${box_height} ${box_depth}"
-</programlisting>
-could be rewritten to ("associative array"-style)
-<programlisting>
-typeset -A -E box=( [width]=56 [height]=10 [depth]=19 )
-print -- "${box[width]} ${box[height]} ${box[depth]}"
-</programlisting>
-or ("compound variable"-style
-<programlisting>
-box=(
- float width=56
- float height=10
- float depth=19
- )
-print -- "${box.width} ${box.height} ${box.depth}"
-</programlisting>
- </para>
- </section>
- </section><!-- end of variables -->
-
-
-
-
-
-
-
- <section xml:id="io">
- <title>I/O</title>
-
- <section xml:id="avoid_echo">
- <title>Avoid using the "<literal>echo</literal>" command for output</title>
- <para>The behaviour of "<literal>echo</literal>" is not portable
- (e.g. System V, BSD, UCB and ksh93/bash shell builtin versions all
- slightly differ in functionality) and should be avoided if possible.
- POSIX defines the "<literal>printf</literal>" command as replacement
- which provides more flexible and portable behaviour.</para>
-
- <note>
- <title>&tag_kshonly;Use "<literal>print</literal>" and not "<literal>echo</literal>" in Korn Shell scripts</title>
- <para>Korn shell scripts should prefer the "<literal>print</literal>"
- builtin which was introduced as replacement for "<literal>echo</literal>".</para>
- <caution>
- <para>Use <literal>$ print -- ${varname}" #</literal> when there is the slightest chance that the
- variable "<literal>varname</literal>" may contain symbols like "-". Or better use "<literal>printf</literal>"
- instead, for example
-<programlisting>
-integer fx
-# do something
-print $fx
-</programlisting>
-may fail if "f" contains a negative value. A better way may be to use
-<programlisting>
-integer fx
-# do something
-printf "%d\n" fx
-</programlisting>
- </para>
- </caution>
- </note>
- </section>
-
- <section xml:id="use_redirect_not_exec_to_open_files">
- <title>&tag_ksh93only;Use <literal>redirect</literal> and not <literal>exec</literal> to open files</title>
- <para>Use <literal>redirect</literal> and not <literal>exec</literal> to open files - <literal>exec</literal>
- will terminate the current function or script if an error occurs while <literal>redirect</literal>
- just returns a non-zero exit code which can be caught.</para>
-<para>Example:
-<programlisting>
-if redirect 5&lt;/etc/profile ; then
- print "file open ok"
- head &lt;&amp;5
-else
- print "could not open file"
-fi
-</programlisting>
- </para>
- </section>
-
- <section xml:id="group_identical_redirections_together">
- <title>&tag_performance;Avoid redirections per command when the output goes into the same file,
- e.g. <literal>$ echo "foo" &gt;xxx ; echo "bar" &gt;&gt;xxx ; echo "baz" &gt;&gt;xxx #</literal></title>
- <para>Each of the redirections above trigger an
- <literal>|open()|,|write()|,|close()|</literal>-sequence. It is much
- more efficient (and faster) to group the rediction into a block,
- e.g. <literal>{ echo "foo" ; echo "bar" ; echo "baz" } &gt;xxx #</literal></para>
- </section>
-
-
- <section xml:id="avoid_using_temporary_files">
- <title>&tag_performance;Avoid the creation of temporary files and store the values in variables instead</title>
- <para>Avoid the creation of temporary files and store the values in variables instead if possible</para>
- <para>
- Example:
-<programlisting>
-ls -1 &gt;xxx
-for i in $(cat xxx) ; do
- do_something ;
-done
-</programlisting>
-can be replaced with
-<programlisting>
-x="$(ls -1)"
-for i in ${x} ; do
- do_something ;
-done
-</programlisting>
- </para>
- <note><para>ksh93 supports binary variables (e.g. <literal>typeset -b varname</literal>) which can hold any value.</para></note>
- </section>
-
-
- <section xml:id="create_subdirs_for_multiple_temporary_files">
- <title>If you create more than one temporary file create an unique subdir</title>
- <para>If you create more than one temporary file create an unique subdir for
- these files and make sure the dir is writable. Make sure you cleanup
- after yourself (unless you are debugging).
- </para>
- </section>
-
-
- <section xml:id="use_dynamic_file_descriptors">
- <title>&tag_ksh93only;Use {n}&lt;file instead of fixed file descriptor numbers</title>
- <para>When opening a file use {n}&lt;file, where <envar>n</envar> is an
- integer variable rather than specifying a fixed descriptor number.</para>
- <para>This is highly recommended in functions to avoid that fixed file
- descriptor numbers interfere with the calling script.</para>
-<example><title>Open a network connection and store the file descriptor number in a variable</title>
-<programlisting>
-function cat_http
-{
- integer netfd
-
-...
-
- # open TCP channel
- redirect {netfd}&lt;&gt;"/dev/tcp/${host}/${port}"
-
- # send HTTP request
- request="GET /${path} HTTP/1.1\n"
- request+="Host: ${host}\n"
- request+="User-Agent: demo code/ksh93 (2007-08-30; $(uname -s -r -p))\n"
- request+="Connection: close\n"
- print "${request}\n" &gt;&amp;${netfd}
-
- # collect response and send it to stdout
- cat &lt;&amp;${netfd}
-
- # close connection
- exec {netfd}&lt;&amp;-
-
-...
-
-}
-</programlisting>
-</example>
- </section>
-
-
- <section xml:id="use_inline_here_documents">
- <title>&tag_ksh93only;&tag_performance;Use inline here documents
- instead of <literal>echo "$x" | command</literal></title>
- <para>Use inline here documents, for example
-<programlisting>
-command &lt;&lt;&lt; $x
-</programlisting>
- rather than
-<programlisting>
-print -r -- "$x" | command
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="use_read_r">
- <title>&tag_ksh93only;Use the <literal>-r</literal> option of <literal>read</literal> to read a line</title>
- <para>Use the <literal>-r</literal> option of <literal>read</literal> to read a line.
- You never know when a line will end in <literal>\</literal> and without a
- <literal>-r</literal> multiple
- lines can be read.</para>
- </section>
-
-
- <section xml:id="print_compound_variables_using_print_C">
- <title>&tag_ksh93only;Print compound variables using <literal>print -C varname</literal> or <literal>print -v varname</literal></title>
- <para>Print compound variables using <literal>print -C varname</literal> or
- <literal>print -v varname</literal> to make sure that non-printable characters
- are correctly encoded.</para>
-<example><title>Print compound variable with non-printable characters</title>
-<programlisting>
-compound x=(
- a=5
- b="hello"
- c=(
- d=9
- e="$(printf "1\v3")" <co xml:id="co.vertical_tab1" />
- )
-)
-print -v x
-</programlisting>
-<para>will print:</para>
-<screen>
-<computeroutput>(
- a=5
- b=hello
- c=(
- d=9
- e=$'1\0133' <co xml:id="co.vertical_tab2" />
- )
-)</computeroutput>
-</screen>
-<calloutlist>
- <callout arearefs="co.vertical_tab1 co.vertical_tab2">
- <para>vertical tab, <literal>\v</literal>, octal=<literal>\013</literal>.</para>
- </callout>
-</calloutlist>
-</example>
- </section>
-
- <section xml:id="command_name_before_redirections">
- <title>Put the command name and arguments before redirections</title>
- <para>Put the command name and arguments before redirections.
- You can legally do <literal>$ &gt; file date</literal> instead of <literal>date &gt; file</literal>
- but don't do it.</para>
- </section>
-
- <section xml:id="enable_gmacs_editor_mode_for_user_prompts">
- <title>&tag_ksh93only;Enable the <literal>gmacs</literal> editor
- mode when reading user input using the <literal>read</literal> builtin</title>
- <para>Enable the <literal>gmacs</literal>editor mode before reading user
- input using the <literal>read</literal> builtin to enable the use of
- cursor+backspace+delete keys in the edit line</para>
-<example><title>Prompt user for a string with gmacs editor mode enabled</title>
-<programlisting>
-set -o gmacs <co xml:id="co.enable_gmacs" />
-typeset inputstring="default value"
-...
-read -v<co xml:id="co.read_v" /> inputstring<co xml:id="co.readvar" />?"Please enter a string: "<co xml:id="co.prompt" />
-...
-printf "The user entered the following string: '%s'\n" "${inputstring}"
-
-...
-</programlisting>
-<calloutlist>
- <callout arearefs="co.enable_gmacs">
- <para>Enable gmacs editor mode.</para>
- </callout>
- <callout arearefs="co.read_v">
- <para>The value of the variable is displayed and used as a default value.</para>
- </callout>
- <callout arearefs="co.readvar">
- <para>Variable used to store the result.</para>
- </callout>
- <callout arearefs="co.prompt">
- <para>Prompt string which is displayed in stderr.</para>
- </callout>
-</calloutlist>
-</example>
- </section>
- </section><!-- end of I/O -->
-
-
-
-
-
-
- <section xml:id="math">
- <title>Math</title>
-
- <section xml:id="use_builtin_arithmetic_expressions">
- <title>&tag_kshonly;&tag_performance;Use builtin arithmetic expressions instead of external applications</title>
- <para>Use builtin (POSIX shell) arithmetic expressions instead of
- <filename>expr</filename>,
- <filename>bc</filename>,
- <filename>dc</filename>,
- <filename>awk</filename>,
- <filename>nawk</filename> or
- <filename>perl</filename>.
- </para>
- <note>
- <para>ksh93 supports C99-like floating-point arithmetic including special values
- such as
- <simplelist type="inline">
- <member>+Inf</member>
- <member>-Inf</member>
- <member>+NaN</member>
- <member>-NaN</member>
- </simplelist>.
- </para>
- </note>
- </section>
-
-
- <section xml:id="use_floating_point_arithmetic_expressions">
- <title>&tag_ksh93only; Use floating-point arithmetic expressions if
- calculations may trigger a division by zero or other exceptions</title>
- <para>Use floating-point arithmetic expressions if calculations may
- trigger a division by zero or other exceptions - floating point arithmetic expressions in
- ksh93 support special values such as <literal>+Inf</literal>/<literal>-Inf</literal> and
- <literal>+NaN</literal>/<literal>-NaN</literal> which can greatly simplify testing for
- error conditions, e.g. instead of a <literal>trap</literal> or explicit
- <literal>if ... then... else</literal> checks for every sub-expression
- you can check the results for such special values.
- </para>
- <para>Example:
-<screen>
-$ <userinput>ksh93 -c 'integer i=0 j=5 ; print -- "x=$((j/i)) "'</userinput>
-<computeroutput>ksh93: line 1: j/i: divide by zero</computeroutput>
-$ <userinput>ksh93 -c 'float i=0 j=-5 ; print -- "x=$((j/i)) "'</userinput>
-<computeroutput>x=-Inf</computeroutput>
-</screen>
- </para>
- </section>
-
-
- <section xml:id="use_printf_a_for_passing_float_values">
- <title>&tag_ksh93only; Use <literal>printf "%a"</literal> when passing floating-point values</title>
- <para>Use <literal>printf "%a"</literal> when passing floating-point values between scripts or
- as output of a function to avoid rounding errors when converting between
- bases.</para>
- <para>
- Example:
-<programlisting>
-function xxx
-{
- float val
-
- (( val=sin(5.) ))
- printf "%a\n" val
-}
-float out
-(( out=$(xxx) ))
-xxx
-print -- $out
-</programlisting>
-This will print:
-<programlisting>
--0.9589242747
--0x1.eaf81f5e09933226af13e5563bc6p-01
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="put_constants_into_readonly_variables">
- <title>&tag_kshonly;&tag_performance;Put constant values into readonly variables</title>
- <para>Put constant values into readonly variables</para>
- <para>For example:
-<programlisting>
-float -r M_PI=3.14159265358979323846
-</programlisting>
-or
-<programlisting>
-float M_PI=3.14159265358979323846
-readonly M_PI
-</programlisting>
- </para>
- </section>
-
-
- <section xml:id="avoid_unnecessary_string_number_conversions">
- <title>&tag_kshonly;&tag_performance;Avoid string to number
- (and/or number to string) conversions in arithmetic expressions
- expressions</title>
- <para>Avoid string to number and/or number to string conversions in
- arithmetic expressions expressions to avoid performance degradation
- and rounding errors.</para>
- <example><title>(( x=$x*2 )) vs. (( x=x*2 ))</title>
-<programlisting>
-float x
-...
-(( x=$x*2 ))
-</programlisting>
-<para>
-will convert the variable "x" (stored in the machine's native
-<literal>|long double|</literal> datatype) to a string value in base10 format,
-apply pattern expansion (globbing), then insert this string into the
-arithmetic expressions and parse the value which converts it into the internal |long double| datatype format again.
-This is both slow and generates rounding errors when converting the floating-point value between
-the internal base2 and the base10 representation of the string.
-</para>
-<para>
-The correct usage would be:
-</para>
-<programlisting>
-float x
-...
-(( x=x*2 ))
-</programlisting>
-<para>
-e.g. omit the '$' because it's (at least) redundant within arithmetic expressions.
-</para>
- </example>
-
-
- <example><title>x=$(( y+5.5 )) vs. (( x=y+5.5 ))</title>
-<programlisting>
-float x
-float y=7.1
-...
-x=$(( y+5.5 ))
-</programlisting>
-<para>
-will calculate the value of <literal>y+5.5</literal>, convert it to a
-base-10 string value amd assign the value to the floating-point variable
-<literal>x</literal> again which will convert the string value back to the
-internal |long double| datatype format again.
-</para>
-<para>
-The correct usage would be:
-</para>
-<programlisting>
-float x
-float y=7.1
-...
-(( x=y+5.5 ))
-</programlisting>
-<para>
-i.e. this will save the string conversions and avoid any base2--&gt;base10--&gt;base2-conversions.
-</para>
- </example>
- </section>
-
-
- <section xml:id="set_lc_numeric_when_using_floating_point">
- <title>&tag_ksh93only;Set <envar>LC_NUMERIC</envar> when using floating-point constants</title>
- <para>Set <envar>LC_NUMERIC</envar> when using floating-point constants to avoid problems with radix-point
- representations which differ from the representation used in the script, for example the <literal>de_DE.*</literal> locale
- use ',' instead of '.' as default radix point symbol.</para>
- <para>For example:
-<programlisting>
-# Make sure all math stuff runs in the "C" locale to avoid problems with alternative
-# radix point representations (e.g. ',' instead of '.' in de_DE.*-locales). This
-# needs to be set _before_ any floating-point constants are defined in this script)
-if [[ "${LC_ALL}" != "" ]] ; then
- export \
- LC_MONETARY="${LC_ALL}" \
- LC_MESSAGES="${LC_ALL}" \
- LC_COLLATE="${LC_ALL}" \
- LC_CTYPE="${LC_ALL}"
- unset LC_ALL
-fi
-export LC_NUMERIC=C
-...
-float -r M_PI=3.14159265358979323846
-</programlisting>
- </para>
-
- <note><para>The environment variable <envar>LC_ALL</envar> always overrides all other <envar>LC_*</envar> variables,
- including <envar>LC_NUMERIC</envar>. The script should always protect itself against custom <envar>LC_NUMERIC</envar> and
- <envar>LC_ALL</envar> values as shown in the example above.
- </para></note>
- </section>
-
-
-
- </section><!-- end of math -->
-
-
-
-
-
-
- <section xml:id="misc">
- <title>Misc</title>
-
- <section xml:id="debug_use_lineno_in_ps4">
- <title>Put <literal>[${LINENO}]</literal> in your <envar>PS4</envar></title>
- <para>Put <literal>[${LINENO}]</literal> in your <envar>PS4</envar> prompt so that you will get line
- numbers with you run with <literal>-x</literal>. If you are looking at performance
- issues put <literal>$SECONDS</literal> in the <envar>PS4</envar> prompt as well.</para>
- </section>
-
- </section><!-- end of misc -->
-
-
-
-
-</section><!-- end of RULES -->
-
-
-
-
-</article>
diff --git a/usr/src/lib/libsmartsshd/Makefile b/usr/src/lib/libsmartsshd/Makefile
new file mode 100644
index 0000000000..50d9545ef1
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/Makefile
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+_msg:
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libsmartsshd/Makefile.com b/usr/src/lib/libsmartsshd/Makefile.com
new file mode 100644
index 0000000000..1c189a88d8
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/Makefile.com
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+LIBRARY= libsmartsshd.a
+VERS= .1
+OBJECTS= sshd-plugin.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+SRCDIR = ../common
+SRCS = $(OBJECTS:%.o=$(SRCDIR)/%.c)
+
+CPPFLAGS += -I$(SRCDIR) -D_REENTRANT -D_FILE_OFFSET_BITS=64
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -ldoor -lmd5
+
+$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libsmartsshd/amd64/Makefile b/usr/src/lib/libsmartsshd/amd64/Makefile
new file mode 100644
index 0000000000..31be0ef7e6
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libsmartsshd/common/llib-lsmartsshd b/usr/src/lib/libsmartsshd/common/llib-lsmartsshd
new file mode 100644
index 0000000000..ace7017d41
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/common/llib-lsmartsshd
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+/*
+ *
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
diff --git a/usr/src/lib/libsmartsshd/common/mapfile-vers b/usr/src/lib/libsmartsshd/common/mapfile-vers
new file mode 100644
index 0000000000..c3c6fe4946
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/common/mapfile-vers
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.1 {
+ global:
+ sshd_user_rsa_key_allowed;
+ sshd_user_dsa_key_allowed;
+ sshd_user_ecdsa_key_allowed;
+ sshd_user_key_allowed;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libsmartsshd/common/sshd-plugin.c b/usr/src/lib/libsmartsshd/common/sshd-plugin.c
new file mode 100644
index 0000000000..a6463cea12
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/common/sshd-plugin.c
@@ -0,0 +1,193 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <alloca.h>
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/rsa.h>
+
+#include <md5.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LOG_OOM(SZ) (void) fprintf(stderr, "Cannot alloca %d bytes\n", SZ)
+
+static const char *DOOR = "/var/tmp/._joyent_sshd_key_is_authorized";
+static const char *REQ_FMT_STR = "%s %d %s"; /* name uid fp */
+static const int RETURN_SZ = 2;
+
+static const int MAX_ATTEMPTS = 2;
+static const int SLEEP_PERIOD = 1;
+
+static int
+sshd_allowed_in_capi(struct passwd *pw, const char *fp)
+{
+ int allowed = 0;
+ int fd = -1;
+ int blen = 0;
+ int attempts = 0;
+ char *buf = NULL;
+ door_arg_t door_args = {0};
+
+ if (pw == NULL || fp == NULL)
+ return (0);
+
+ blen = snprintf(NULL, 0, REQ_FMT_STR, pw->pw_name, pw->pw_uid, fp) + 1;
+
+ buf = (char *)alloca(blen);
+ if (buf == NULL) {
+ LOG_OOM(blen);
+ return (0);
+ }
+
+ (void) snprintf(buf, blen, REQ_FMT_STR, pw->pw_name, pw->pw_uid, fp);
+ door_args.data_ptr = buf;
+ door_args.data_size = blen;
+
+ door_args.rsize = RETURN_SZ;
+ door_args.rbuf = alloca(RETURN_SZ);
+ if (door_args.rbuf == NULL) {
+ LOG_OOM(RETURN_SZ);
+ return (0);
+ }
+ (void) memset(door_args.rbuf, 0, RETURN_SZ);
+
+ do {
+ fd = open(DOOR, O_RDWR);
+ if (fd < 0) {
+ if (errno == ENOENT) {
+ /*
+ * On systems which are not running SmartLogin,
+ * such as vanilla SmartOS, the door will be
+ * completely absent. The sleep/retry loop is
+ * skipped in this case to keep the login
+ * process more lively.
+ */
+ perror("smartplugin: door does not exist");
+ return (0);
+ }
+ perror("smartplugin: open (of door FD) failed");
+ } else if (door_call(fd, &door_args) < 0) {
+ perror("smartplugin: door_call failed");
+ } else {
+ allowed = atoi(door_args.rbuf);
+ if (door_args.rsize > RETURN_SZ) {
+ /*
+ * Given what we know about the SmartLogin
+ * daemon on the other end of the door, this
+ * should never occur. An assert might be
+ * preferable, but that is avoided since the
+ * error can be handled.
+ */
+ (void) munmap(door_args.rbuf, door_args.rsize);
+ }
+ return (allowed);
+ }
+ if (++attempts < MAX_ATTEMPTS) {
+ (void) sleep(SLEEP_PERIOD);
+ }
+ } while (attempts < MAX_ATTEMPTS);
+
+ return (0);
+}
+
+static int
+tohexstr(uchar_t *bytes, size_t blen, char *hexstr, size_t hexlen)
+{
+ size_t i, j;
+ const char hexlist[] = "0123456789abcdef";
+
+ if (hexlen < 1)
+ return (-1);
+ for (i = 0, j = 0; i < blen; i++) {
+ /*
+ * We need 3 bytes output per input byte -- the third byte is
+ * either for a : or the \0 at the end.
+ */
+ if (hexlen < (j + 3))
+ return (-1);
+ hexstr[j++] = hexlist[(bytes[i] >> 4) & 0xf];
+ hexstr[j++] = hexlist[bytes[i] & 0xf];
+ if (i + 1 < blen)
+ hexstr[j++] = ':';
+ }
+ hexstr[j] = '\0';
+ return (0);
+}
+
+/* ARGSUSED */
+int
+sshd_user_key_allowed(struct passwd *pw, const char *type,
+ const unsigned char *buf, size_t size)
+{
+ unsigned char md5buf[MD5_DIGEST_LENGTH];
+ /*
+ * Will contain the fingerprint MD5 in colonhex format. Need 3 bytes
+ * per MD5 byte: two for hex digits, plus one for either ':' or '\0'.
+ */
+ char hex[MD5_DIGEST_LENGTH * 3];
+
+ md5_calc(md5buf, buf, size);
+ if (tohexstr(md5buf, sizeof (md5buf), hex, sizeof (hex)) != 0)
+ return (0);
+ return (sshd_allowed_in_capi(pw, hex));
+}
+
+/* ARGSUSED */
+int
+sshd_user_rsa_key_allowed(struct passwd *pw, RSA *key, const char *fp)
+{
+ return (sshd_allowed_in_capi(pw, fp));
+}
+
+/* ARGSUSED */
+int
+sshd_user_dsa_key_allowed(struct passwd *pw, DSA *key, const char *fp)
+{
+ return (sshd_allowed_in_capi(pw, fp));
+}
+
+/* ARGSUSED */
+int
+sshd_user_ecdsa_key_allowed(struct passwd *pw, DSA *key, const char *fp)
+{
+ return (sshd_allowed_in_capi(pw, fp));
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/usr/src/lib/libsmartsshd/i386/Makefile b/usr/src/lib/libsmartsshd/i386/Makefile
new file mode 100644
index 0000000000..2bfe8001d9
--- /dev/null
+++ b/usr/src/lib/libsmartsshd/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libumem/amd64/umem_genasm.c b/usr/src/lib/libumem/amd64/umem_genasm.c
index 00cc18ab67..ba68cb2d37 100644
--- a/usr/src/lib/libumem/amd64/umem_genasm.c
+++ b/usr/src/lib/libumem/amd64/umem_genasm.c
@@ -69,8 +69,6 @@
#include <umem_impl.h>
#include "umem_base.h"
-#include <stdio.h>
-
const int umem_genasm_supported = 1;
static uintptr_t umem_genasm_mptr = (uintptr_t)&_malloc;
static size_t umem_genasm_msize = 576;
diff --git a/usr/src/lib/libvnd/Makefile b/usr/src/lib/libvnd/Makefile
new file mode 100644
index 0000000000..1352adb8e4
--- /dev/null
+++ b/usr/src/lib/libvnd/Makefile
@@ -0,0 +1,50 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.lib
+
+HDRS = libvnd.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+TYPECHECK_LIB = libvnd.so.1
+TYPELIST = \
+ vnd_ioc_attach_t \
+ vnd_ioc_link_t \
+ vnd_ioc_unlink_t \
+ vnd_ioc_buf_t \
+ vnd_ioc_info_t
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS) $(TYPECHECK)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libvnd/Makefile.com b/usr/src/lib/libvnd/Makefile.com
new file mode 100644
index 0000000000..3c6896de11
--- /dev/null
+++ b/usr/src/lib/libvnd/Makefile.com
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../../Makefile.lib
+
+LIBRARY = libvnd.a
+VERS = .1
+OBJECTS = libvnd.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc
+CPPFLAGS += -I../common
+
+SRCDIR = ../common
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libvnd/amd64/Makefile b/usr/src/lib/libvnd/amd64/Makefile
new file mode 100644
index 0000000000..15d904c616
--- /dev/null
+++ b/usr/src/lib/libvnd/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libvnd/common/libvnd.c b/usr/src/lib/libvnd/common/libvnd.c
new file mode 100644
index 0000000000..8972f6cf5a
--- /dev/null
+++ b/usr/src/lib/libvnd/common/libvnd.c
@@ -0,0 +1,550 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdio.h>
+#include <zone.h>
+#include <assert.h>
+#include <sys/sysmacros.h>
+
+#include <sys/vnd.h>
+#include <libvnd.h>
+
+struct vnd_handle {
+ int vh_fd;
+ uint32_t vh_errno;
+ int vh_syserr;
+};
+
+static const char *vnd_strerror_tbl[] = {
+ "no error", /* VND_E_SUCCESS */
+ "not enough memory available", /* VND_E_NOMEM */
+ "no such datalink", /* VND_E_NODATALINK */
+ "datalink not of type DL_ETHER", /* VND_E_NOTETHER */
+ "unknown dlpi failure", /* VND_E_DLPIINVAL */
+ "DL_ATTACH_REQ failed", /* VND_E_ATTACHFAIL */
+ "DL_BIND_REQ failed", /* VND_E_PROMISCFAIL */
+ "DL_PROMISCON_REQ failed", /* VND_E_PROMISCFAIL */
+ "DLD_CAPAB_DIRECT enable failed", /* VND_E_DIRECTFAIL */
+ "bad datalink capability", /* VND_E_CAPACKINVAL */
+ "bad datalink subcapability", /* VND_E_SUBCAPINVAL */
+ "bad dld version", /* VND_E_DLDBADVERS */
+ "failed to create kstats", /* VND_E_KSTATCREATE */
+ "no such vnd link", /* VND_E_NODEV */
+ "netstack doesn't exist", /* VND_E_NONETSTACK */
+ "device already associated", /* VND_E_ASSOCIATED */
+ "device already attached", /* VND_E_ATTACHED */
+ "device already linked", /* VND_E_LINKED */
+ "invalid name", /* VND_E_BADNAME */
+ "permission denied", /* VND_E_PERM */
+ "no such zone", /* VND_E_NOZONE */
+ "failed to initialize vnd stream module", /* VND_E_STRINIT */
+ "device not attached", /* VND_E_NOTATTACHED */
+ "device not linked", /* VND_E_NOTLINKED */
+ "another device has the same link name", /* VND_E_LINKEXISTS */
+ "failed to create minor node", /* VND_E_MINORNODE */
+ "requested buffer size is too large", /* VND_E_BUFTOOBIG */
+ "requested buffer size is too small", /* VND_E_TOOSMALL */
+ "unable to obtain exclusive access to dlpi link, link busy",
+ /* VND_E_DLEXCL */
+ "DLD direct capability not supported over data link",
+ /* VND_E_DIRECTNOTSUP */
+ "invalid property size", /* VND_E_BADPROPSIZE */
+ "invalid property", /* VND_E_BADPROP */
+ "property is read only", /* VND_E_PROPRDONLY */
+ "unexpected system error", /* VND_E_SYS */
+ "capabilities invalid, pass-through module detected",
+ /* VND_E_CAPABPASS */
+ "unknown error" /* VND_E_UNKNOWN */
+};
+
+vnd_errno_t
+vnd_errno(vnd_handle_t *vhp)
+{
+ return (vhp->vh_errno);
+}
+
+const char *
+vnd_strerror(vnd_errno_t err)
+{
+ if (err >= VND_E_UNKNOWN)
+ err = VND_E_UNKNOWN;
+ return (vnd_strerror_tbl[err]);
+}
+
+int
+vnd_syserrno(vnd_handle_t *vhp)
+{
+ return (vhp->vh_syserr);
+}
+
+const char *
+vnd_strsyserror(int err)
+{
+ return (strerror(err));
+}
+
+static int
+vnd_ioc_return(vnd_handle_t *vhp, uint32_t err)
+{
+ if (err != VND_E_SUCCESS) {
+ vhp->vh_errno = err;
+ vhp->vh_syserr = 0;
+ } else {
+ if (errno == EFAULT)
+ abort();
+ vhp->vh_errno = VND_E_SYS;
+ vhp->vh_syserr = errno;
+ }
+ return (-1);
+}
+
+void
+vnd_close(vnd_handle_t *vhp)
+{
+ int ret;
+
+ if (vhp->vh_fd >= 0) {
+ ret = close(vhp->vh_fd);
+ assert(ret == 0);
+ }
+ free(vhp);
+}
+
+static int
+vnd_link(vnd_handle_t *vhp, const char *name)
+{
+ vnd_ioc_link_t vil;
+
+ if (strlen(name) >= VND_NAMELEN) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ (void) strlcpy(vil.vil_name, name, sizeof (vil.vil_name));
+ vil.vil_errno = VND_E_SUCCESS;
+ if (ioctl(vhp->vh_fd, VND_IOC_LINK, &vil) != 0)
+ return (vnd_ioc_return(vhp, vil.vil_errno));
+
+ return (0);
+}
+
+static vnd_handle_t *
+vnd_open_ctl(vnd_errno_t *vnderr, int *syserr)
+{
+ int fd;
+ vnd_handle_t *vhp;
+
+ vhp = malloc(sizeof (vnd_handle_t));
+ if (vhp == NULL) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_NOMEM;
+ if (syserr != NULL)
+ *syserr = 0;
+ return (NULL);
+ }
+ bzero(vhp, sizeof (vnd_handle_t));
+
+ fd = open("/dev/vnd/ctl", O_RDWR);
+ if (fd < 0) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_SYS;
+ if (syserr != NULL)
+ *syserr = errno;
+ free(vhp);
+ return (NULL);
+ }
+
+ vhp->vh_fd = fd;
+ return (vhp);
+}
+
+vnd_handle_t *
+vnd_create(const char *zonename, const char *datalink, const char *linkname,
+ vnd_errno_t *vnderr, int *syserr)
+{
+ int ret;
+ vnd_handle_t *vhp;
+ vnd_ioc_attach_t via;
+ zoneid_t zid;
+
+ if (strlen(datalink) >= VND_NAMELEN) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_BADNAME;
+ if (syserr != NULL)
+ *syserr = 0;
+ return (NULL);
+ }
+
+ vhp = vnd_open_ctl(vnderr, syserr);
+ if (vhp == NULL)
+ return (NULL); /* errno set for us */
+
+ if (zonename != NULL) {
+ zid = getzoneidbyname(zonename);
+ if (zid == -1) {
+ vnd_close(vhp);
+ if (vnderr != NULL)
+ *vnderr = VND_E_NOZONE;
+ if (syserr != NULL)
+ *syserr = 0;
+ return (NULL);
+ }
+ via.via_zoneid = zid;
+ } else {
+ via.via_zoneid = -1;
+ }
+
+ (void) strlcpy(via.via_name, datalink, sizeof (via.via_name));
+ via.via_errno = VND_E_SUCCESS;
+ if (ioctl(vhp->vh_fd, VND_IOC_ATTACH, &via) != 0) {
+ if (via.via_errno != VND_E_SUCCESS) {
+ if (vnderr != NULL)
+ *vnderr = via.via_errno;
+ if (syserr != NULL)
+ *syserr = 0;
+ } else {
+ if (vnderr != NULL)
+ *vnderr = VND_E_SYS;
+ if (syserr != NULL)
+ *syserr = errno;
+ }
+ vnd_close(vhp);
+ return (NULL);
+ }
+
+ ret = vnd_link(vhp, linkname);
+ if (ret != 0) {
+ if (vnderr != NULL)
+ *vnderr = vhp->vh_errno;
+ if (syserr != NULL)
+ *syserr = vhp->vh_syserr;
+ vnd_close(vhp);
+ return (NULL);
+ }
+
+ if (vnderr != NULL)
+ *vnderr = VND_E_SUCCESS;
+ if (syserr != NULL)
+ *syserr = 0;
+
+ return (vhp);
+}
+
+vnd_handle_t *
+vnd_open(const char *zone, const char *link, vnd_errno_t *vnderr, int *syserr)
+{
+ int fd, ret;
+ char path[MAXPATHLEN];
+ vnd_handle_t *vhp;
+
+ if (zone != NULL)
+ ret = snprintf(path, sizeof (path), "/dev/vnd/zone/%s/%s",
+ zone, link);
+ else
+ ret = snprintf(path, sizeof (path), "/dev/vnd/%s", link);
+
+ if (ret >= sizeof (path)) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_BADNAME;
+ if (syserr != NULL)
+ *syserr = 0;
+ return (NULL);
+ }
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_SYS;
+ if (syserr != NULL)
+ *syserr = errno;
+ return (NULL);
+ }
+
+ vhp = malloc(sizeof (vnd_handle_t));
+ if (vhp == NULL) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_NOMEM;
+ if (syserr != NULL)
+ *syserr = 0;
+ ret = close(fd);
+ assert(ret == 0);
+ return (NULL);
+ }
+
+ bzero(vhp, sizeof (vnd_handle_t));
+ vhp->vh_fd = fd;
+
+ return (vhp);
+}
+
+int
+vnd_unlink(vnd_handle_t *vhp)
+{
+ vnd_ioc_unlink_t viu;
+ viu.viu_errno = VND_E_SUCCESS;
+
+ if (ioctl(vhp->vh_fd, VND_IOC_UNLINK, &viu) != 0)
+ return (vnd_ioc_return(vhp, viu.viu_errno));
+
+ return (0);
+}
+
+int
+vnd_pollfd(vnd_handle_t *vhp)
+{
+ return (vhp->vh_fd);
+}
+
+int
+vnd_walk(vnd_walk_cb_t func, void *arg, vnd_errno_t *vnderr, int *syserr)
+{
+ vnd_handle_t *vhp;
+ vnd_ioc_list_t vl;
+ vnd_ioc_info_t *viip;
+ int i, ret;
+
+ vl.vl_nents = 0;
+ vl.vl_ents = NULL;
+
+ vhp = vnd_open_ctl(vnderr, syserr);
+ if (vhp == NULL)
+ return (-1); /* errno is set for us */
+
+ /* VND_IOC_LIST only returns generic errnos */
+ if (ioctl(vhp->vh_fd, VND_IOC_LIST, &vl) != 0) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_SYS;
+ if (syserr != NULL)
+ *syserr = errno;
+ (void) vnd_ioc_return(vhp, VND_E_SUCCESS);
+ vnd_close(vhp);
+
+ return (-1);
+ }
+
+ if (vl.vl_actents == 0) {
+ vnd_close(vhp);
+ return (0);
+ }
+
+ viip = malloc(sizeof (vnd_ioc_info_t) * vl.vl_actents);
+ if (viip == NULL) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_NOMEM;
+ if (syserr != NULL)
+ *syserr = 0;
+ vnd_close(vhp);
+ return (-1);
+ }
+
+ vl.vl_nents = vl.vl_actents;
+ vl.vl_ents = viip;
+
+ if (ioctl(vhp->vh_fd, VND_IOC_LIST, &vl) != 0) {
+ if (vnderr != NULL)
+ *vnderr = VND_E_SYS;
+ if (syserr != NULL)
+ *syserr = errno;
+ (void) vnd_ioc_return(vhp, VND_E_SUCCESS);
+ free(viip);
+ vnd_close(vhp);
+ return (-1);
+ }
+
+ ret = 0;
+ for (i = 0; i < MIN(vl.vl_nents, vl.vl_actents); i++) {
+ if (func((vnd_info_t *)(viip + i), arg) != 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ free(viip);
+ vnd_close(vhp);
+
+ return (ret);
+}
+
+static int
+vnd_prop_readonly(vnd_handle_t *vhp)
+{
+ vhp->vh_syserr = 0;
+ vhp->vh_errno = VND_E_PROPRDONLY;
+ return (-1);
+}
+
+/*ARGSUSED*/
+static int
+vnd_prop_getbuf(vnd_handle_t *vhp, int cmd, void *buf, size_t len)
+{
+ vnd_ioc_buf_t vib;
+ vnd_prop_buf_t *vpbp = (vnd_prop_buf_t *)buf;
+ vib.vib_errno = 0;
+
+ if (ioctl(vhp->vh_fd, cmd, &vib) != 0)
+ return (vnd_ioc_return(vhp, vib.vib_errno));
+
+ vpbp->vpb_size = vib.vib_size;
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+vnd_prop_setbuf(vnd_handle_t *vhp, int cmd, void *buf, size_t len)
+{
+ vnd_ioc_buf_t vib;
+ vnd_prop_buf_t *vpbp = (vnd_prop_buf_t *)buf;
+
+ vib.vib_errno = 0;
+ vib.vib_size = vpbp->vpb_size;
+ if (ioctl(vhp->vh_fd, cmd, &vib) != 0)
+ return (vnd_ioc_return(vhp, vib.vib_errno));
+
+ return (0);
+}
+
+typedef int (*vpt_prop_f)(vnd_handle_t *, int, void *, size_t);
+typedef struct vnd_prop_tab {
+ vnd_prop_t vpt_prop;
+ size_t vpt_size;
+ int vpt_ioctl_get;
+ int vpt_ioctl_set;
+ vpt_prop_f vpt_get;
+ vpt_prop_f vpt_set;
+} vnd_prop_tab_t;
+
+static vnd_prop_tab_t vnd_props[] = {
+ { VND_PROP_RXBUF, sizeof (vnd_prop_buf_t), VND_IOC_GETRXBUF,
+ VND_IOC_SETRXBUF, vnd_prop_getbuf, vnd_prop_setbuf},
+ { VND_PROP_TXBUF, sizeof (vnd_prop_buf_t), VND_IOC_GETTXBUF,
+ VND_IOC_SETTXBUF, vnd_prop_getbuf, vnd_prop_setbuf },
+ { VND_PROP_MAXBUF, sizeof (vnd_prop_buf_t), VND_IOC_GETMAXBUF,
+ -1, vnd_prop_getbuf, NULL },
+ { VND_PROP_MINTU, sizeof (vnd_prop_buf_t), VND_IOC_GETMINTU,
+ -1, vnd_prop_getbuf, NULL },
+ { VND_PROP_MAXTU, sizeof (vnd_prop_buf_t), VND_IOC_GETMAXTU,
+ -1, vnd_prop_getbuf, NULL },
+ { VND_PROP_MAX }
+};
+
+static int
+vnd_prop(vnd_handle_t *vhp, vnd_prop_t prop, void *buf, size_t len,
+ boolean_t get)
+{
+ vnd_prop_tab_t *vpt;
+
+ for (vpt = vnd_props; vpt->vpt_prop != VND_PROP_MAX; vpt++) {
+ if (vpt->vpt_prop != prop)
+ continue;
+
+ if (len != vpt->vpt_size) {
+ vhp->vh_errno = VND_E_BADPROPSIZE;
+ vhp->vh_syserr = 0;
+ return (-1);
+ }
+
+ if (get == B_TRUE) {
+ return (vpt->vpt_get(vhp, vpt->vpt_ioctl_get, buf,
+ len));
+ } else {
+ if (vpt->vpt_set == NULL)
+ return (vnd_prop_readonly(vhp));
+ return (vpt->vpt_set(vhp, vpt->vpt_ioctl_set, buf,
+ len));
+ }
+ }
+
+ vhp->vh_errno = VND_E_BADPROP;
+ vhp->vh_syserr = 0;
+ return (-1);
+}
+
+int
+vnd_prop_get(vnd_handle_t *vhp, vnd_prop_t prop, void *buf, size_t len)
+{
+ return (vnd_prop(vhp, prop, buf, len, B_TRUE));
+}
+
+int
+vnd_prop_set(vnd_handle_t *vhp, vnd_prop_t prop, void *buf, size_t len)
+{
+ return (vnd_prop(vhp, prop, buf, len, B_FALSE));
+}
+
+int
+vnd_prop_writeable(vnd_prop_t prop, boolean_t *write)
+{
+ vnd_prop_tab_t *vpt;
+
+ for (vpt = vnd_props; vpt->vpt_prop != VND_PROP_MAX; vpt++) {
+ if (vpt->vpt_prop != prop)
+ continue;
+
+ *write = (vpt->vpt_set != NULL);
+ return (0);
+ }
+
+ return (-1);
+}
+
+int
+vnd_prop_iter(vnd_handle_t *vhp, vnd_prop_iter_f func, void *arg)
+{
+ int i;
+
+ for (i = 0; i < VND_PROP_MAX; i++) {
+ if (func(vhp, i, arg) != 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+vnd_frameio_read(vnd_handle_t *vhp, frameio_t *fiop)
+{
+ int ret;
+
+ ret = ioctl(vhp->vh_fd, VND_IOC_FRAMEIO_READ, fiop);
+ if (ret == -1) {
+ vhp->vh_errno = VND_E_SYS;
+ vhp->vh_syserr = errno;
+ }
+
+ return (ret);
+}
+
+int
+vnd_frameio_write(vnd_handle_t *vhp, frameio_t *fiop)
+{
+ int ret;
+
+ ret = ioctl(vhp->vh_fd, VND_IOC_FRAMEIO_WRITE, fiop);
+ if (ret == -1) {
+ vhp->vh_errno = VND_E_SYS;
+ vhp->vh_syserr = errno;
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libvnd/common/libvnd.h b/usr/src/lib/libvnd/common/libvnd.h
new file mode 100644
index 0000000000..ea92f113b6
--- /dev/null
+++ b/usr/src/lib/libvnd/common/libvnd.h
@@ -0,0 +1,84 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+#ifndef _LIBVND_H
+#define _LIBVND_H
+
+/*
+ * libvnd interfaces
+ */
+
+#include <stdint.h>
+#include <sys/vnd_errno.h>
+#include <sys/frameio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBVND_NAMELEN 32
+
+typedef struct vnd_handle vnd_handle_t;
+
+extern vnd_handle_t *vnd_create(const char *, const char *, const char *,
+ vnd_errno_t *, int *);
+extern vnd_handle_t *vnd_open(const char *, const char *, vnd_errno_t *, int *);
+extern int vnd_unlink(vnd_handle_t *);
+extern void vnd_close(vnd_handle_t *);
+extern vnd_errno_t vnd_errno(vnd_handle_t *);
+extern int vnd_syserrno(vnd_handle_t *);
+extern const char *vnd_strerror(vnd_errno_t);
+extern const char *vnd_strsyserror(int);
+
+extern int vnd_pollfd(vnd_handle_t *);
+
+typedef struct vnd_info {
+ uint32_t vi_version;
+ zoneid_t vi_zone;
+ char vi_name[LIBVND_NAMELEN];
+ char vi_datalink[LIBVND_NAMELEN];
+} vnd_info_t;
+
+typedef int (*vnd_walk_cb_t)(vnd_info_t *, void *);
+extern int vnd_walk(vnd_walk_cb_t, void *, vnd_errno_t *, int *);
+
+typedef enum vnd_prop {
+ VND_PROP_RXBUF = 0,
+ VND_PROP_TXBUF,
+ VND_PROP_MAXBUF,
+ VND_PROP_MINTU,
+ VND_PROP_MAXTU,
+ VND_PROP_MAX
+} vnd_prop_t;
+
+typedef struct vnd_prop_buf {
+ uint64_t vpb_size;
+} vnd_prop_buf_t;
+
+extern int vnd_prop_get(vnd_handle_t *, vnd_prop_t, void *, size_t);
+extern int vnd_prop_set(vnd_handle_t *, vnd_prop_t, void *, size_t);
+extern int vnd_prop_writeable(vnd_prop_t, boolean_t *);
+
+typedef int (*vnd_prop_iter_f)(vnd_handle_t *, vnd_prop_t, void *);
+extern int vnd_prop_iter(vnd_handle_t *, vnd_prop_iter_f, void *);
+
+extern int vnd_frameio_read(vnd_handle_t *, frameio_t *);
+extern int vnd_frameio_write(vnd_handle_t *, frameio_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVND_H */
diff --git a/usr/src/lib/libvnd/common/llib-lvnd b/usr/src/lib/libvnd/common/llib-lvnd
new file mode 100644
index 0000000000..80a4229e32
--- /dev/null
+++ b/usr/src/lib/libvnd/common/llib-lvnd
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libvnd.h>
diff --git a/usr/src/lib/libvnd/common/mapfile-vers b/usr/src/lib/libvnd/common/mapfile-vers
new file mode 100644
index 0000000000..0eb862ab60
--- /dev/null
+++ b/usr/src/lib/libvnd/common/mapfile-vers
@@ -0,0 +1,55 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# TODO When this makes it into illumos we should make it a public interface
+#
+SYMBOL_VERSION ILLUMOSprivate {
+ global:
+ vnd_create;
+ vnd_close;
+ vnd_errno;
+ vnd_frameio_read;
+ vnd_frameio_write;
+ vnd_open;
+ vnd_pollfd;
+ vnd_prop_get;
+ vnd_prop_iter;
+ vnd_prop_set;
+ vnd_prop_writeable;
+ vnd_strerror;
+ vnd_strsyserror;
+ vnd_syserrno;
+ vnd_unlink;
+ vnd_walk;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libvnd/i386/Makefile b/usr/src/lib/libvnd/i386/Makefile
new file mode 100644
index 0000000000..41e699e8f8
--- /dev/null
+++ b/usr/src/lib/libvnd/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc. All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libwanboot/Makefile.com b/usr/src/lib/libwanboot/Makefile.com
index 322bfb51f7..a98a30cfd4 100644
--- a/usr/src/lib/libwanboot/Makefile.com
+++ b/usr/src/lib/libwanboot/Makefile.com
@@ -60,7 +60,7 @@ include ../../Makefile.lib
LIBS += $(LINTLIB)
LDLIBS += -lnvpair -lresolv -lnsl -lsocket -ldevinfo -ldhcputil \
- -linetutil -lc -lcrypto -lssl
+ -linetutil -lc -lsunw_crypto -lsunw_ssl
CPPFLAGS = -I$(SRC)/common/net/wanboot/crypt $(CPPFLAGS.master)
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-parentheses
diff --git a/usr/src/lib/libzdoor/Makefile b/usr/src/lib/libzdoor/Makefile
new file mode 100644
index 0000000000..50d9545ef1
--- /dev/null
+++ b/usr/src/lib/libzdoor/Makefile
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+_msg:
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libzdoor/Makefile.com b/usr/src/lib/libzdoor/Makefile.com
new file mode 100644
index 0000000000..09bde0f1b4
--- /dev/null
+++ b/usr/src/lib/libzdoor/Makefile.com
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY= libzdoor.a
+VERS= .1
+OBJECTS= zdoor.o \
+ zdoor-int.o \
+ ztree.o \
+ zerror.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+SRCDIR = ../common
+SRCS = $(OBJECTS:%.o=$(SRCDIR)/%.c)
+
+CPPFLAGS += -I$(SRCDIR) -D_REENTRANT -D_FILE_OFFSET_BITS=64
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lzonecfg -lcontract
+
+$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libzdoor/amd64/Makefile b/usr/src/lib/libzdoor/amd64/Makefile
new file mode 100644
index 0000000000..31be0ef7e6
--- /dev/null
+++ b/usr/src/lib/libzdoor/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libzdoor/common/llib-lzdoor b/usr/src/lib/libzdoor/common/llib-lzdoor
new file mode 100644
index 0000000000..a21a904b11
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/llib-lzdoor
@@ -0,0 +1,34 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+/*
+ *
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <zdoor.h>
diff --git a/usr/src/lib/libzdoor/common/mapfile-vers b/usr/src/lib/libzdoor/common/mapfile-vers
new file mode 100644
index 0000000000..38eba57ee2
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/mapfile-vers
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2011, Joyent Inc. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.1 {
+ global:
+ zdoor_handle_init;
+ zdoor_handle_destroy;
+ zdoor_open;
+ zdoor_close;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libzdoor/common/zdoor-int.c b/usr/src/lib/libzdoor/common/zdoor-int.c
new file mode 100644
index 0000000000..f77c1453d4
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/zdoor-int.c
@@ -0,0 +1,324 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/fork.h>
+#include <libcontract.h>
+#include <libzonecfg.h>
+#include <sys/contract/process.h>
+#include <sys/ctfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "zdoor-int.h"
+#include "zerror.h"
+
+#define ZDOOR_FMT_STR "/var/tmp/.%s"
+
+
+static int
+init_template(void)
+{
+ int fd = 0;
+ int err = 0;
+
+ fd = open64(CTFS_ROOT "/process/template", O_RDWR);
+ if (fd == -1)
+ return (-1);
+
+ err |= ct_tmpl_set_critical(fd, 0);
+ err |= ct_tmpl_set_informative(fd, 0);
+ err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
+ err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
+ if (err || ct_tmpl_activate(fd)) {
+ (void) close(fd);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+static int
+contract_latest(ctid_t *id)
+{
+ int cfd = 0;
+ int r = 0;
+ ct_stathdl_t st = {0};
+ ctid_t result = {0};
+
+ if ((cfd = open64(CTFS_ROOT "/process/latest", O_RDONLY)) == -1)
+ return (errno);
+ if ((r = ct_status_read(cfd, CTD_COMMON, &st)) != 0) {
+ (void) close(cfd);
+ return (r);
+ }
+
+ result = ct_status_get_id(st);
+ ct_status_free(st);
+ (void) close(cfd);
+
+ *id = result;
+ return (0);
+}
+
+static int
+close_on_exec(int fd)
+{
+ int flags = fcntl(fd, F_GETFD, 0);
+ if ((flags != -1) && (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1))
+ return (0);
+ return (-1);
+}
+
+static int
+contract_open(ctid_t ctid, const char *type, const char *file, int oflag)
+{
+ char path[PATH_MAX];
+ int n = 0;
+ int fd = 0;
+
+ if (type == NULL)
+ type = "all";
+
+ n = snprintf(path, PATH_MAX, CTFS_ROOT "/%s/%ld/%s", type, ctid, file);
+ if (n >= sizeof (path)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ fd = open64(path, oflag);
+ if (fd != -1) {
+ if (close_on_exec(fd) == -1) {
+ int err = errno;
+ (void) close(fd);
+ errno = err;
+ return (-1);
+ }
+ }
+ return (fd);
+}
+
+static int
+contract_abandon_id(ctid_t ctid)
+{
+ int fd = 0;
+ int err = 0;
+
+ fd = contract_open(ctid, "all", "ctl", O_WRONLY);
+ if (fd == -1)
+ return (errno);
+
+ err = ct_ctl_abandon(fd);
+ (void) close(fd);
+
+ return (err);
+}
+
+/*
+ * zdoor_fattach(zone,service,door,detach_only) is heavily borrowed from
+ * zonestatd. Basically this forks, zone_enter's the targeted zone,
+ * fattaches to /var/tmp/.<service> with the door you've opened.
+ * detach_only gets passed in on door_stop to fdetach in the targeted zone.
+ * Note that this code really does require all the contract calls, which are
+ * all the static functions preceding this (have a look at zone_enter; without
+ * that code zone_enter will kick back EINVAL).
+ */
+int
+zdoor_fattach(zoneid_t zoneid, const char *service, int door, int detach_only)
+{
+ int fd = 0;
+ int len = 0;
+ int pid = 0;
+ int stat = 0;
+ int tmpl_fd = 0;
+ char path[MAXPATHLEN] = {0};
+ ctid_t ct = -1;
+
+ if (zoneid < 0) {
+ zdoor_debug("zdoor_fattach: zoneid < 0");
+ return (ZDOOR_ARGS_ERROR);
+ }
+
+ if (service == NULL) {
+ zdoor_debug("zdoor_fattach: NULL service");
+ return (ZDOOR_ARGS_ERROR);
+ }
+
+ if ((tmpl_fd = init_template()) < 0) {
+ zdoor_warn("zdoor_fattach: init contract for %d:%s failed",
+ zoneid, service);
+ return (ZDOOR_ERROR);
+ }
+
+ len = snprintf(NULL, 0, ZDOOR_FMT_STR, service) + 1;
+ if (len > MAXPATHLEN)
+ return (ZDOOR_ARGS_ERROR);
+ (void) snprintf(path, len, ZDOOR_FMT_STR, service);
+
+ zdoor_info("zdoor_fattach: ensuring %s", path);
+
+ pid = fork();
+ if (pid < 0) {
+ (void) ct_tmpl_clear(tmpl_fd);
+ zdoor_error("zdoor_fattach: unable to fork for zone_enter: %s",
+ strerror(errno));
+ return (ZDOOR_OK);
+ }
+
+ if (pid == 0) {
+ zdoor_debug("zdoor_fattach(CHILD): starting");
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+ if (zone_enter(zoneid) != 0) {
+ zdoor_debug("zdoor_fattach(CHILD): zone_enter fail %s",
+ strerror(errno));
+ if (errno == EINVAL) {
+ _exit(0);
+ }
+ _exit(1);
+ }
+ (void) fdetach(path);
+ (void) unlink(path);
+ if (detach_only) {
+ zdoor_debug("zdoor_fattach(CHILD): detach only, done");
+ _exit(0);
+ }
+ fd = open(path, O_CREAT|O_RDWR, 0644);
+ if (fd < 0) {
+ zdoor_debug("zdoor_fattach(CHILD): open failed: %s",
+ strerror(errno));
+ _exit(2);
+ }
+ if (fattach(door, path) != 0) {
+ zdoor_debug("zdoor_fattach(CHILD): fattach failed: %s",
+ strerror(errno));
+ _exit(3);
+ }
+ _exit(0);
+ }
+ if (contract_latest(&ct) == -1)
+ ct = -1;
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+ (void) contract_abandon_id(ct);
+
+ zdoor_debug("zdoor_fattach: waiting for child...");
+ while (waitpid(pid, &stat, 0) != pid)
+ ;
+ if (WIFEXITED(stat) && WEXITSTATUS(stat) == 0) {
+ zdoor_debug(" child exited with success");
+ zdoor_debug("zdoor_fattach: returning ZDOOR_OK");
+ return (ZDOOR_OK);
+ }
+
+ zdoor_debug(" child exited with %d", WEXITSTATUS(stat));
+ zdoor_debug("zdoor_fattach: returning ZDOOR_ERROR");
+ return (ZDOOR_ERROR);
+}
+
+/*
+ * zdoor_zone_is_running(zone) returns 1 if the specified zone is running, or 0
+ * if it is any other state. It additionally eats any other errors it
+ * encounters and returns 0 upon encountering them.
+ */
+boolean_t
+zdoor_zone_is_running(zoneid_t zoneid)
+{
+ zone_state_t state;
+ char zone[ZONENAME_MAX];
+ if (zoneid < 0)
+ return (B_FALSE);
+
+ if (getzonenamebyid(zoneid, zone, ZONENAME_MAX) < 0)
+ return (B_FALSE);
+
+ if (!zone_get_state((char *)zone, &state) == Z_OK)
+ return (B_FALSE);
+
+ return (state == ZONE_STATE_RUNNING);
+}
+
+/*
+ * zdoor_cookie_create simply allocates and initializes
+ * memory. Returns NULL on any error.
+ */
+zdoor_cookie_t *
+zdoor_cookie_create(const char *zonename, const char *service,
+const void *biscuit)
+{
+ zdoor_cookie_t *cookie = NULL;
+
+ if (zonename == NULL || service == NULL)
+ return (NULL);
+
+ cookie = (zdoor_cookie_t *)calloc(1, sizeof (zdoor_cookie_t));
+ if (cookie == NULL) {
+ OUT_OF_MEMORY();
+ return (NULL);
+ }
+ cookie->zdc_biscuit = (void *)biscuit;
+ cookie->zdc_zonename = strdup((char *)zonename);
+ if (cookie->zdc_zonename == NULL) {
+ zdoor_cookie_free(cookie);
+ OUT_OF_MEMORY();
+ return (NULL);
+ }
+ cookie->zdc_service = strdup((char *)service);
+ if (cookie->zdc_service == NULL) {
+ zdoor_cookie_free(cookie);
+ OUT_OF_MEMORY();
+ return (NULL);
+ }
+
+ return (cookie);
+}
+
+/*
+ * zdoor_cookie_free(cookie) cleans up any memory associated with the
+ * specified cookie.
+ */
+void
+zdoor_cookie_free(zdoor_cookie_t *cookie)
+{
+ if (cookie == NULL)
+ return;
+
+ if (cookie->zdc_zonename != NULL) {
+ free(cookie->zdc_zonename);
+ cookie->zdc_zonename = NULL;
+ }
+
+ if (cookie->zdc_service != NULL) {
+ free(cookie->zdc_service);
+ cookie->zdc_service = NULL;
+ }
+
+ free(cookie);
+}
diff --git a/usr/src/lib/libzdoor/common/zdoor-int.h b/usr/src/lib/libzdoor/common/zdoor-int.h
new file mode 100644
index 0000000000..782452c426
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/zdoor-int.h
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ZDOOR_INT_H
+#define _ZDOOR_INT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <pthread.h>
+#include <zdoor.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum zdoor_action_t {
+ ZDOOR_ACTION_NOOP,
+ ZDOOR_ACTION_STOP,
+ ZDOOR_ACTION_START
+} zdoor_action_t;
+
+struct zdoor_handle {
+ pthread_mutex_t zdh_lock;
+ void *zdh_zonecfg_handle;
+ void *zdh_ztree;
+};
+
+zdoor_cookie_t *zdoor_cookie_create(const char *zonename, const char *service,
+ const void *biscuit);
+
+void zdoor_cookie_free(zdoor_cookie_t *cookie);
+
+boolean_t zdoor_zone_is_running(zoneid_t zoneid);
+
+int zdoor_fattach(zoneid_t zoneid, const char *service, int door,
+ int detach_only);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZDOOR_INT_H */
diff --git a/usr/src/lib/libzdoor/common/zdoor.c b/usr/src/lib/libzdoor/common/zdoor.c
new file mode 100644
index 0000000000..f2996b4e2d
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/zdoor.c
@@ -0,0 +1,437 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <alloca.h>
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libzonecfg.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stropts.h>
+#include <unistd.h>
+#include <zdoor.h>
+#include <zone.h>
+
+#include "zdoor-int.h"
+#include "zerror.h"
+#include "ztree.h"
+
+extern void *
+zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
+ const char *newstate, const char *oldstate,
+ hrtime_t when, void *p), void *p);
+
+extern void
+zonecfg_notify_unbind(void *handle);
+
+/*
+ * _callback(cookie, door_args...) is our private function that we tell
+ * the Solaris door API about. This function does some sanity checking on
+ * arguments and issues a callback to the owner of this door. That API
+ * will return us memory that needs to be sent back to the client on the
+ * other end of the door, but since the door_return API never gives you
+ * back control of the function, this does a simple alloca/memcpy and
+ * frees up the memory pointed to by the parent. While this really doesn't
+ * let a client do much other than pass a simple struct of primitives (or
+ * more likely more common a char *), that's the way the door API works,
+ * and so this isn't really imposing any restriction that didn't already
+ * need to be dealt with by someone. This is why the zdoor_result structure
+ * takes a char *, rather than a void * for the data pointer.
+ */
+static void
+_callback(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
+ uint_t n_desc)
+{
+ zdoor_result_t *result = NULL;
+ void *door_response = NULL;
+ int size = 0;
+ dtree_entry_t *entry = (dtree_entry_t *)cookie;
+
+ if (entry == NULL) {
+ zdoor_warn("_callback: NULL cookie? door_returning");
+ (void) door_return(NULL, 0, NULL, 0);
+ }
+
+ (void) pthread_mutex_lock(&entry->dte_parent->zte_parent->zdh_lock);
+ zdoor_debug("_callback: calling back with %p", entry->dte_cookie);
+ result = entry->dte_callback(entry->dte_cookie, argp, arg_size);
+ zdoor_debug("_callback: app callback returned %p", result);
+ (void) pthread_mutex_unlock(&entry->dte_parent->zte_parent->zdh_lock);
+
+ if (result == NULL) {
+ zdoor_debug("_callback: door_returning NULL");
+ (void) door_return(NULL, 0, NULL, 0);
+ }
+
+ if (result->zdr_data != NULL && result->zdr_size > 0) {
+ door_response = alloca(result->zdr_size);
+ if (door_response != NULL) {
+ size = result->zdr_size;
+ (void) memcpy(door_response,
+ (void *) result->zdr_data, size);
+ }
+ }
+
+ if (result->zdr_data != NULL)
+ free(result->zdr_data);
+ free(result);
+
+ zdoor_debug("_callback: door_returning %p, %d", door_response, size);
+ (void) door_return(door_response, size, NULL, 0);
+}
+
+static void
+zdoor_stop(dtree_entry_t *entry)
+{
+ zoneid_t zid = -1;
+
+ if (entry == NULL) {
+ zdoor_debug("zdoor_stop: NULL arguments");
+ return;
+ }
+
+ zdoor_debug("zdoor_stop: entry=%p, zone=%s, service=%s",
+ entry, entry->dte_parent->zte_zonename, entry->dte_service);
+
+ zid = getzoneidbyname(entry->dte_parent->zte_zonename);
+ (void) zdoor_fattach(zid, entry->dte_service, entry->dte_door, 1);
+ (void) door_revoke(entry->dte_door);
+ entry->dte_door = -1;
+
+ zdoor_debug("zdoor_stop returning");
+}
+
+/*
+ * zdoor_create is called both by the main API
+ * call zdoor_open, as well as by the zone_monitor code upon a zone restart
+ * (assuming it already has a door in it). This code assumes that the
+ * permissions were correct (e.g., the target door is not a GZ, that this
+ * program is being run out of the GZ), but does not assume that the target
+ * door file has not changed out from under us, so that is explicitly rechecked.
+ *
+ * This also assumes the parent has already locked handle.
+ */
+static int
+zdoor_create(dtree_entry_t *entry)
+{
+ int status = ZDOOR_OK;
+ zoneid_t zid = -1;
+ zdoor_handle_t handle = NULL;
+
+ if (entry == NULL) {
+ zdoor_debug("zdoor_create: NULL arguments");
+ return (ZDOOR_ARGS_ERROR);
+ }
+
+ zdoor_debug("zdoor_create: entry=%p, zone=%s, service=%s",
+ entry, entry->dte_parent->zte_zonename, entry->dte_service);
+
+ handle = entry->dte_parent->zte_parent;
+
+ zid = getzoneidbyname(entry->dte_parent->zte_zonename);
+ if (zid < 0) {
+ zdoor_info("zdoor_create: %s is a non-existient zone",
+ entry->dte_parent->zte_zonename);
+ return (ZDOOR_ERROR);
+ }
+ if (!zdoor_zone_is_running(zid)) {
+ zdoor_debug("zdoor_create: %s is not running",
+ entry->dte_parent->zte_zonename);
+ return (ZDOOR_ZONE_NOT_RUNNING);
+ }
+
+ entry->dte_door = door_create(_callback, entry, 0);
+ zdoor_info("zdoor_create: door_create returned %d", entry->dte_door);
+ if (entry->dte_door < 0) {
+ zdoor_stop(entry);
+ return (ZDOOR_ERROR);
+ }
+
+ status = zdoor_fattach(zid, entry->dte_service, entry->dte_door, 0);
+
+ zdoor_debug("zdoor_create: returning %d", status);
+ return (status);
+}
+
+
+/*
+ * door_visitor(entry) is a callback from the ztree code that checks whether
+ * or not we should be taking some action on a given door. Note that the
+ * callpath to this API is:
+ * SYSTEM ->
+ * zone_monitor ->
+ * ztree_walk ->
+ * door_visitor
+ *
+ * Which is important to note that this API assumes that all things needing
+ * locking are locked by a parent caller (which is the zone_monitor).
+ */
+static void
+zdoor_visitor(dtree_entry_t *entry)
+{
+ if (entry == NULL) {
+ zdoor_info("zdoor_visitor: entered with NULL entry");
+ return;
+ }
+
+ zdoor_debug("zdoor_visitor: entered for entry=%p, service=%s",
+ entry, entry->dte_service);
+
+ if (entry->dte_parent->zte_action == ZDOOR_ACTION_STOP) {
+ zdoor_debug(" stopping zdoor");
+ zdoor_stop(entry);
+ } else if (entry->dte_parent->zte_action == ZDOOR_ACTION_START) {
+ zdoor_debug(" starting zdoor");
+ if (zdoor_create(entry) != ZDOOR_OK) {
+ zdoor_error("door_visitor: Unable to restart zdoor\n");
+ }
+ }
+}
+
+/*
+ * zone_monitor(zonename, zid, newstate, oldstate, when, cookie) is our
+ * registered callback with libzonecfg to notify us of any changes to a
+ * given zone. This activates a walk on all doors for a zone iff the state
+ * is changing from running or into running.
+ */
+static int
+zone_monitor(const char *zonename, zoneid_t zid, const char *newstate,
+ const char *oldstate, hrtime_t when, void *p)
+{
+ zdoor_handle_t handle = (zdoor_handle_t)p;
+ ztree_entry_t *entry = NULL;
+
+ if (handle == NULL) {
+ zdoor_warn("zone_monitor: entered with NULL handle?");
+ return (-1);
+ }
+
+ zdoor_info("zone_monitor: zone=%s, zid=%d, newst=%s, oldst=%s, p=%p",
+ zonename, zid, newstate, oldstate, p);
+
+ (void) pthread_mutex_lock(&(handle->zdh_lock));
+ entry = ztree_zone_find(handle, zonename);
+ if (entry != NULL) {
+ zdoor_debug(" found entry in ztree");
+ entry->zte_action = ZDOOR_ACTION_NOOP;
+ if (strcmp("running", newstate) == 0) {
+ if (strcmp("ready", oldstate) == 0)
+ entry->zte_action = ZDOOR_ACTION_START;
+ } else if (strcmp("shutting_down", newstate) == 0) {
+ if (strcmp("running", oldstate) == 0)
+ entry->zte_action = ZDOOR_ACTION_STOP;
+ }
+ zdoor_debug(" set state to: %d", entry->zte_action);
+ if (entry->zte_action != ZDOOR_ACTION_NOOP)
+ ztree_walk_doors(handle, zonename);
+ }
+ (void) pthread_mutex_unlock(&(handle->zdh_lock));
+
+ zdoor_info("zone_monitor: returning");
+ return (0);
+}
+
+zdoor_handle_t
+zdoor_handle_init()
+{
+ zdoor_handle_t handle = NULL;
+
+ zdoor_debug("zdoor_handle_init entered");
+
+ handle = (zdoor_handle_t)calloc(1, sizeof (struct zdoor_handle));
+ if (handle == NULL) {
+ OUT_OF_MEMORY();
+ return (NULL);
+ }
+
+ (void) pthread_mutex_init(&(handle->zdh_lock), NULL);
+ handle->zdh_zonecfg_handle = zonecfg_notify_bind(zone_monitor, handle);
+ if (handle->zdh_zonecfg_handle == NULL) {
+ zdoor_error("zonecfg_notify_bind failure: %s", strerror(errno));
+ return (NULL);
+ }
+
+ zdoor_debug("zdoor_handle_init returning %p", handle);
+ return (handle);
+}
+
+void
+zdoor_handle_destroy(zdoor_handle_t handle)
+{
+ if (handle == NULL) {
+ zdoor_debug("zdoor_handle_destroy: NULL arguments");
+ return;
+ }
+
+ zdoor_debug("zdoor_handle_destroy: handle=%p", handle);
+
+ (void) pthread_mutex_lock(&(handle->zdh_lock));
+ zonecfg_notify_unbind(handle->zdh_zonecfg_handle);
+ (void) pthread_mutex_unlock(&(handle->zdh_lock));
+ (void) pthread_mutex_destroy(&(handle->zdh_lock));
+ free(handle);
+}
+
+/*
+ * zdoor_open(zone, service, biscuit, callback) is the main public facing API in
+ * libzdoor. It will open a door with the name .[service] under
+ * [zonepath]/root/var/tmp, where [zonepath] is resolved on the fly. Note this
+ * API can only be invoked from the global zone, and will not allow you to open
+ * a zdoor in the global zone.
+ */
+int
+zdoor_open(zdoor_handle_t handle, const char *zonename, const char *service,
+ void *biscuit, zdoor_callback callback)
+{
+ zdoor_cookie_t *zdoor_cookie = NULL;
+ int rc = -1;
+ int status = ZDOOR_OK;
+ zoneid_t zid = -1;
+ dtree_entry_t *entry = NULL;
+
+ if (handle == NULL || zonename == NULL ||
+ service == NULL || callback == NULL) {
+ zdoor_debug("zdoor_open: NULL arguments");
+ return (ZDOOR_ARGS_ERROR);
+ }
+ zdoor_debug("zdoor_open: entered: handle=%p, zone=%s, service=%s",
+ handle, zonename, service);
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ zdoor_warn("zdoor_open: not invoked from global zone");
+ return (ZDOOR_NOT_GLOBAL_ZONE);
+ }
+
+
+ zid = getzoneidbyname(zonename);
+ if (zid < 0) {
+ zdoor_info("zdoor_open: %s is a non-existent zone", zonename);
+ return (ZDOOR_ARGS_ERROR);
+ }
+
+ if (zid == GLOBAL_ZONEID) {
+ zdoor_warn("zdoor_open: zdoors not allowed in global zone");
+ return (ZDOOR_ZONE_FORBIDDEN);
+ }
+
+ if (!zdoor_zone_is_running(zid)) {
+ zdoor_info("zdoor_open: %s is not running", zonename);
+ return (ZDOOR_ZONE_NOT_RUNNING);
+ }
+
+ zdoor_cookie = zdoor_cookie_create(zonename, service, biscuit);
+ if (zdoor_cookie == NULL) {
+ OUT_OF_MEMORY();
+ return (ZDOOR_OUT_OF_MEMORY);
+ }
+
+ (void) pthread_mutex_lock(&(handle->zdh_lock));
+ rc = ztree_zone_add(handle, zonename, zdoor_visitor);
+ if (rc != ZTREE_SUCCESS && rc != ZTREE_ALREADY_EXISTS) {
+ zdoor_debug("zdoor_open: unable to add zone to ztree: %d", rc);
+ status = ZDOOR_ERROR;
+ goto out;
+ }
+ rc = ztree_door_add(handle, zonename, service, callback,
+ zdoor_cookie);
+ if (rc != ZTREE_SUCCESS) {
+ zdoor_debug("zdoor_open: unable to add door to ztree: %d", rc);
+ if (rc == ZTREE_ALREADY_EXISTS) {
+ zdoor_warn("service %s already has a zdoor", service);
+ }
+ status = ZDOOR_ERROR;
+ goto out;
+ }
+
+ entry = ztree_door_find(handle, zonename, service);
+ if (entry == NULL) {
+ zdoor_debug("zdoor_open: unable to find door in ztree?");
+ status = ZDOOR_ERROR;
+ goto out;
+ }
+ if (zdoor_create(entry) != ZDOOR_OK) {
+ zdoor_info("zdoor_open: zdoor_create failed.");
+ status = ZDOOR_ERROR;
+ goto out;
+ }
+out:
+ if (status != ZDOOR_OK) {
+ zdoor_debug("zdoor_open: status not ok, stopping and cleaning");
+ zdoor_stop(entry);
+ ztree_door_remove(handle, entry);
+ zdoor_cookie_free(zdoor_cookie);
+ }
+ (void) pthread_mutex_unlock(&(handle->zdh_lock));
+ zdoor_debug("zdoor_open: returning %d", status);
+ return (status);
+}
+
+/*
+ * zdoor_close(zone, service) unregisters a previously created zdoor, and
+ * returns the biscuit provided at creation time, so the caller can free it.
+ * Returns NULL on any error.
+ */
+void *
+zdoor_close(zdoor_handle_t handle, const char *zonename, const char *service)
+{
+ dtree_entry_t *entry = NULL;
+ zdoor_cookie_t *cookie = NULL;
+ void *biscuit = NULL;
+
+ if (handle == NULL || zonename == NULL || service == NULL) {
+ zdoor_debug("zdoor_close: NULL arguments");
+ return (NULL);
+ }
+
+ zdoor_debug("zdoor_close: entered handle=%p, zone=%s, service=%s",
+ handle, zonename, service);
+
+ (void) pthread_mutex_lock(&(handle->zdh_lock));
+
+ entry = ztree_door_find(handle, zonename, service);
+ if (entry != NULL) {
+ zdoor_debug("zdoor_close: found door in ztree, stopping");
+ zdoor_stop(entry);
+ cookie = ztree_door_remove(handle, entry);
+ if (cookie != NULL) {
+ biscuit = cookie->zdc_biscuit;
+ zdoor_cookie_free(cookie);
+ }
+ } else {
+ zdoor_debug("zdoor_close: didn't find door in ztree");
+ }
+
+ (void) pthread_mutex_unlock(&(handle->zdh_lock));
+
+ zdoor_debug("zdoor_close: returning %p", biscuit);
+ return (biscuit);
+}
diff --git a/usr/src/lib/libzdoor/common/zerror.c b/usr/src/lib/libzdoor/common/zerror.c
new file mode 100644
index 0000000000..5ccb449e1b
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/zerror.c
@@ -0,0 +1,117 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "zerror.h"
+
+static const char *PREFIX = "%s ZDOOR:%s:T(%d): ";
+
+static const char *DEBUG_ENV_VAR = "ZDOOR_TRACE";
+
+static boolean_t
+is_debug_enabled()
+{
+ boolean_t enabled = B_FALSE;
+ const char *_envp = getenv(DEBUG_ENV_VAR);
+ if (_envp != NULL && atoi(_envp) >= 2)
+ enabled = B_TRUE;
+
+ return (enabled);
+}
+
+static boolean_t
+is_info_enabled()
+{
+ boolean_t enabled = B_FALSE;
+ const char *_envp = getenv(DEBUG_ENV_VAR);
+ if (_envp != NULL && atoi(_envp) >= 1)
+ enabled = B_TRUE;
+
+ return (enabled);
+}
+
+void
+zdoor_debug(const char *fmt, ...)
+{
+ va_list alist;
+
+ if (!is_debug_enabled())
+ return;
+
+ va_start(alist, fmt);
+
+ (void) fprintf(stderr, PREFIX, __TIME__, "DEBUG", pthread_self());
+ (void) vfprintf(stderr, fmt, alist);
+ (void) fprintf(stderr, "\n");
+ va_end(alist);
+}
+
+void
+zdoor_info(const char *fmt, ...)
+{
+ va_list alist;
+
+ if (!is_info_enabled())
+ return;
+
+ va_start(alist, fmt);
+
+ (void) fprintf(stderr, PREFIX, __TIME__, "INFO", pthread_self());
+ (void) vfprintf(stderr, fmt, alist);
+ (void) fprintf(stderr, "\n");
+ va_end(alist);
+}
+
+void
+zdoor_warn(const char *fmt, ...)
+{
+ va_list alist;
+
+ va_start(alist, fmt);
+
+ (void) fprintf(stderr, PREFIX, __TIME__, "WARN", pthread_self());
+ (void) vfprintf(stderr, fmt, alist);
+ (void) fprintf(stderr, "\n");
+ va_end(alist);
+}
+
+void
+zdoor_error(const char *fmt, ...)
+{
+ va_list alist;
+
+ va_start(alist, fmt);
+
+ (void) fprintf(stderr, PREFIX, __TIME__, "ERROR", pthread_self());
+ (void) vfprintf(stderr, fmt, alist);
+ (void) fprintf(stderr, "\n");
+ va_end(alist);
+}
diff --git a/usr/src/lib/libzdoor/common/zerror.h b/usr/src/lib/libzdoor/common/zerror.h
new file mode 100644
index 0000000000..afc848fcea
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/zerror.h
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ZERROR_H
+#define _ZERROR_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void zdoor_debug(const char *fmt, ...);
+extern void zdoor_info(const char *fmt, ...);
+extern void zdoor_warn(const char *fmt, ...);
+extern void zdoor_error(const char *fmt, ...);
+
+#define OUT_OF_MEMORY() \
+ zdoor_error("Out of Memory at %s:%d", __FILE__, __LINE__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZERROR_H */
diff --git a/usr/src/lib/libzdoor/common/ztree.c b/usr/src/lib/libzdoor/common/ztree.c
new file mode 100644
index 0000000000..25c67f62fb
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/ztree.c
@@ -0,0 +1,344 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <search.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "zerror.h"
+#include "ztree.h"
+
+
+/*
+ * ztree is just a helpful wrapper over a tsearch binary tree that deals with
+ * all of the libzdoor types.
+ *
+ * So what this ztree actually is is a tree of trees. The outer tree is a tree
+ * of zones, and each node holds a tree of doors.
+ */
+
+/*
+ * _ztree_compare(p1, p2) is the tsearch callback for comparing the "outer"
+ * tree (e.g., the one of zones).
+ */
+static int
+_ztree_compare(const void *p1, const void *p2)
+{
+ ztree_entry_t *z1 = (ztree_entry_t *)p1;
+ ztree_entry_t *z2 = (ztree_entry_t *)p2;
+
+ if (z1 == NULL && z2 == NULL)
+ return (0);
+ if (z1 == NULL && z2 != NULL)
+ return (-1);
+ if (z1 != NULL && z2 == NULL)
+ return (1);
+
+ return (strcmp(z1->zte_zonename, z2->zte_zonename));
+}
+
+/*
+ * _dtree_compare(p1, p2) is the tsearch callback for comparing the "inner"
+ * tree (e.g., the one of doors).
+ */
+static int
+_dtree_compare(const void *p1, const void *p2)
+{
+ dtree_entry_t *d1 = (dtree_entry_t *)p1;
+ dtree_entry_t *d2 = (dtree_entry_t *)p2;
+
+ if (d1 == NULL && d2 == NULL)
+ return (0);
+ if (d1 == NULL && d2 != NULL)
+ return (-1);
+ if (d1 != NULL && d2 == NULL)
+ return (1);
+
+ return (strcmp(d1->dte_service, d2->dte_service));
+}
+
+static void
+ztree_entry_free(ztree_entry_t *entry)
+{
+ if (entry == NULL)
+ return;
+
+ if (entry->zte_zonename != NULL)
+ free(entry->zte_zonename);
+
+ free(entry);
+}
+
+static void
+dtree_entry_free(dtree_entry_t *entry)
+{
+ if (entry == NULL)
+ return;
+
+ if (entry->dte_service)
+ free(entry->dte_service);
+
+ free(entry);
+}
+
+
+/*
+ * ztree_zone_add inserts a new zone into the tree iff
+ * there is not already an entry for that zone. This method returns one of
+ * four possible return codes, ZTREE_SUCCESS on :), ZTREE_ARGUMENT_ERROR if
+ * zone is NULL, ZTREE_ERROR if there is internal failure (e.g., OOM), and
+ * ZTREE_ALREADY_EXISTS if the zone is already in the tree.
+ */
+int
+ztree_zone_add(struct zdoor_handle *handle, const char *zonename,
+ztree_door_visitor visitor)
+{
+ ztree_entry_t *entry = NULL;
+ void *ret = NULL;
+ int status = ZTREE_SUCCESS;
+
+ if (handle == NULL || zonename == NULL)
+ return (ZTREE_ARGUMENT_ERROR);
+
+ entry = (ztree_entry_t *)calloc(1, sizeof (ztree_entry_t));
+ if (entry == NULL) {
+ OUT_OF_MEMORY();
+ return (ZTREE_ERROR);
+ }
+ entry->zte_zonename = strdup(zonename);
+ if (entry->zte_zonename == NULL) {
+ ztree_entry_free(entry);
+ OUT_OF_MEMORY();
+ return (ZTREE_ERROR);
+ }
+ entry->zte_action = ZDOOR_ACTION_NOOP;
+ entry->zte_parent = handle;
+ entry->zte_visitor = visitor;
+
+ ret = tsearch(entry, &(handle->zdh_ztree), _ztree_compare);
+ if (ret == NULL) {
+ ztree_entry_free(entry);
+ status = ZTREE_ERROR;
+ OUT_OF_MEMORY();
+ } else if ((*(ztree_entry_t **)ret) != entry) {
+ ztree_entry_free(entry);
+ status = ZTREE_ALREADY_EXISTS;
+ }
+
+ return (status);
+}
+
+
+/*
+ * ztree_zone_find returns the entry in the "outer" tree representing
+ * this zone, if it exists, NULL otherwise.
+ */
+ztree_entry_t *
+ztree_zone_find(struct zdoor_handle *handle, const char *zonename)
+{
+ ztree_entry_t key = {0};
+ void *ret = NULL;
+
+ if (handle == NULL || zonename == NULL)
+ return (NULL);
+
+ key.zte_zonename = (char *)zonename;
+ ret = tfind(&key, &(handle->zdh_ztree), _ztree_compare);
+
+ return (ret != NULL ? *(ztree_entry_t **)ret : NULL);
+}
+
+
+/*
+ * ztree_zone_remove removes an entry from the "outer" zone iff the
+ * zone exists. The cookie set by the creator is returned.
+ */
+void
+ztree_zone_remove(struct zdoor_handle *handle, ztree_entry_t *entry)
+{
+ if (handle == NULL || entry == NULL)
+ return;
+
+ tdelete(entry, &(handle->zdh_ztree), _ztree_compare);
+ ztree_entry_free(entry);
+}
+
+
+/*
+ * ztree_door_add inserts a new door into the inner tree iff
+ * there is not already an entry for that door. This method returns one of
+ * four possible return codes, ZTREE_SUCCESS on :), ZTREE_ARGUMENT_ERROR if
+ * zone is NULL, ZTREE_ERROR if there is internal failure (e.g., OOM), and
+ * ZTREE_ALREADY_EXISTS if the door is already in the tree.
+ */
+int
+ztree_door_add(struct zdoor_handle *handle, const char *zonename,
+const char *service, zdoor_callback callback, zdoor_cookie_t *cookie)
+{
+ dtree_entry_t *entry = NULL;
+ ztree_entry_t *znode = NULL;
+ void *ret = NULL;
+ int status = ZTREE_SUCCESS;
+
+ if (handle == NULL || zonename == NULL || service == NULL)
+ return (ZTREE_ARGUMENT_ERROR);
+
+ znode = ztree_zone_find(handle, zonename);
+ if (znode == NULL)
+ return (ZTREE_NOT_FOUND);
+
+ entry = (dtree_entry_t *)calloc(1, sizeof (dtree_entry_t));
+ if (entry == NULL) {
+ OUT_OF_MEMORY();
+ return (ZTREE_ERROR);
+ }
+ entry->dte_parent = znode;
+ entry->dte_callback = callback;
+ entry->dte_cookie = cookie;
+ entry->dte_service = strdup(service);
+ if (entry->dte_service == NULL) {
+ free(entry);
+ OUT_OF_MEMORY();
+ return (ZTREE_ERROR);
+ }
+
+ ret = tsearch(entry, &(znode->zte_door_tree), _dtree_compare);
+ if (ret == NULL) {
+ dtree_entry_free(entry);
+ OUT_OF_MEMORY();
+ status = ZTREE_ERROR;
+ } else if ((*(dtree_entry_t **)ret) != entry) {
+ dtree_entry_free(entry);
+ status = ZTREE_ALREADY_EXISTS;
+ } else {
+ znode->zte_num_doors++;
+ }
+
+ return (status);
+}
+
+
+/*
+ * ztree_door_find returns the entry in the "inner" tree
+ * representing this zone, if it exists, NULL otherwise.
+ */
+dtree_entry_t *
+ztree_door_find(struct zdoor_handle *handle, const char *zonename,
+const char *service)
+{
+ dtree_entry_t key = {0};
+ ztree_entry_t *znode = NULL;
+ void *ret = NULL;
+
+ if (handle == NULL || zonename == NULL || service == NULL)
+ return (NULL);
+
+ znode = ztree_zone_find(handle, zonename);
+ if (znode == NULL)
+ return (NULL);
+
+ key.dte_service = (char *)service;
+ ret = tfind(&key, &(znode->zte_door_tree), _dtree_compare);
+
+ return (ret != NULL ? *(dtree_entry_t **)ret : NULL);
+}
+
+
+/*
+ * ztree_door_remove(zone, door) removes a node from the inner tree iff
+ * both the door and zone exist. Note this frees the node as well. The
+ * cookie set by the creator is returned.
+ */
+zdoor_cookie_t *
+ztree_door_remove(struct zdoor_handle *handle, dtree_entry_t *entry)
+{
+ zdoor_cookie_t *cookie = NULL;
+ ztree_entry_t *znode = NULL;
+
+ if (handle == NULL || entry == NULL)
+ return (NULL);
+
+ znode = entry->dte_parent;
+ cookie = entry->dte_cookie;
+
+ tdelete(entry, &(znode->zte_door_tree), _dtree_compare);
+ dtree_entry_free(entry);
+
+ znode->zte_num_doors--;
+ if (znode->zte_num_doors == 0) {
+ zdoor_debug("ztree: zone %s has no doors left, removing",
+ znode->zte_zonename);
+ ztree_zone_remove(handle, znode);
+ }
+
+ return (cookie);
+}
+
+
+/*
+ * _ztree_door_visitor(nodep, which, depth) is the private function we use
+ * to wrap up tsearch's goofy API. We're really just using this to ensure
+ * zdoor doesn't get called > 1 times for a given entity in the ztree.
+ */
+static void
+_ztree_door_visitor(const void *nodep, const VISIT which, const int depth)
+{
+ dtree_entry_t *entry = *(dtree_entry_t **)nodep;
+
+ if (entry == NULL)
+ return;
+
+ switch (which) {
+ case preorder:
+ case endorder:
+ break;
+ case postorder:
+ case leaf:
+ if (entry->dte_parent->zte_visitor != NULL)
+ entry->dte_parent->zte_visitor(entry);
+ break;
+ }
+}
+
+
+/*
+ * ztree_walk_doors(zone) will proceed to visit every node in the "inner" tree
+ * for this zone, and callback the visitor that was registered on tree creation.
+ */
+void
+ztree_walk_doors(struct zdoor_handle *handle, const char *zonename)
+{
+ ztree_entry_t *znode = NULL;
+
+ if (handle == NULL || zonename == NULL)
+ return;
+
+ znode = ztree_zone_find(handle, zonename);
+ if (znode == NULL)
+ return;
+
+ twalk(znode->zte_door_tree, _ztree_door_visitor);
+}
diff --git a/usr/src/lib/libzdoor/common/ztree.h b/usr/src/lib/libzdoor/common/ztree.h
new file mode 100644
index 0000000000..b46dace287
--- /dev/null
+++ b/usr/src/lib/libzdoor/common/ztree.h
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2011 Joyent, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ZTREE_H
+#define _ZTREE_H
+
+#include <zdoor.h>
+#include <zone.h>
+#include "zdoor-int.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dtree_entry;
+
+typedef void (*ztree_door_visitor)(struct dtree_entry *entry);
+
+typedef struct ztree_entry {
+ char *zte_zonename;
+ zdoor_action_t zte_action;
+ int zte_num_doors;
+ void *zte_door_tree;
+ ztree_door_visitor zte_visitor;
+ struct zdoor_handle *zte_parent;
+} ztree_entry_t;
+
+typedef struct dtree_entry {
+ char *dte_service;
+ int dte_door;
+ zdoor_callback dte_callback;
+ zdoor_cookie_t *dte_cookie;
+ ztree_entry_t *dte_parent;
+} dtree_entry_t;
+
+#define ZTREE_SUCCESS 0
+#define ZTREE_ERROR -1
+#define ZTREE_ARGUMENT_ERROR -2
+#define ZTREE_ALREADY_EXISTS -3
+#define ZTREE_NOT_FOUND -4
+
+extern int ztree_zone_add(struct zdoor_handle *handle,
+ const char *zonename, ztree_door_visitor visitor);
+
+extern ztree_entry_t *ztree_zone_find(struct zdoor_handle *handle,
+ const char *zonename);
+
+extern void ztree_zone_remove(struct zdoor_handle *handle,
+ ztree_entry_t *entry);
+
+extern int ztree_door_add(struct zdoor_handle *handle, const char *zonename,
+ const char *service, zdoor_callback callback, zdoor_cookie_t *cookie);
+
+extern dtree_entry_t *ztree_door_find(struct zdoor_handle *handle,
+ const char *zonename, const char *service);
+
+extern zdoor_cookie_t *ztree_door_remove(struct zdoor_handle *handle,
+ dtree_entry_t *entry);
+
+extern void ztree_walk_doors(struct zdoor_handle *handle, const char *zonename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZTREE_H */
diff --git a/usr/src/lib/libzdoor/i386/Makefile b/usr/src/lib/libzdoor/i386/Makefile
new file mode 100644
index 0000000000..2bfe8001d9
--- /dev/null
+++ b/usr/src/lib/libzdoor/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2011 Joyent, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 5f81aa2048..3d324ef2df 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -64,6 +64,7 @@ typedef enum zfs_error {
EZFS_PROPTYPE, /* property does not apply to dataset type */
EZFS_PROPNONINHERIT, /* property is not inheritable */
EZFS_PROPSPACE, /* bad quota or reservation */
+ EZFS_PROPCACHED, /* prop unavail since cachedprops flag set */
EZFS_BADTYPE, /* dataset is not of appropriate type */
EZFS_BUSY, /* pool or dataset is busy */
EZFS_EXISTS, /* pool or dataset already exists */
@@ -196,6 +197,7 @@ extern libzfs_handle_t *zpool_get_handle(zpool_handle_t *);
extern libzfs_handle_t *zfs_get_handle(zfs_handle_t *);
extern void libzfs_print_on_error(libzfs_handle_t *, boolean_t);
+extern void libzfs_set_cachedprops(libzfs_handle_t *, boolean_t);
extern void zfs_save_arguments(int argc, char **, char *, int);
extern int zpool_log_history(libzfs_handle_t *, const char *);
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index 9f55741bc9..2c32553839 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -315,6 +315,10 @@ get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
{
libzfs_handle_t *hdl = zhp->zfs_hdl;
+ if (hdl->libzfs_cachedprops &&
+ libzfs_cmd_set_cachedprops(hdl, zc) != 0)
+ return (-1);
+
(void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
@@ -2095,6 +2099,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
case ZFS_PROP_NORMALIZE:
case ZFS_PROP_UTF8ONLY:
case ZFS_PROP_CASE:
+ if (zhp->zfs_hdl->libzfs_cachedprops) {
+ return (zfs_error(zhp->zfs_hdl, EZFS_PROPCACHED,
+ "property unavailable since not cached"));
+ }
+
if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) ||
zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1);
@@ -2406,6 +2415,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
const char *str;
const char *strval;
boolean_t received = zfs_is_recvd_props_mode(zhp);
+ boolean_t printerr;
/*
* Check to see if this property applies to our object
@@ -2416,6 +2426,16 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
if (received && zfs_prop_readonly(prop))
return (-1);
+ if (zhp->zfs_hdl->libzfs_cachedprops &&
+ zfs_prop_cacheable(prop)) {
+ printerr = zhp->zfs_hdl->libzfs_printerr;
+ libzfs_print_on_error(zhp->zfs_hdl, B_FALSE);
+ (void) zfs_error(zhp->zfs_hdl, EZFS_PROPCACHED,
+ "property unavailable since not cached");
+ libzfs_print_on_error(zhp->zfs_hdl, printerr);
+ return (-1);
+ }
+
if (src)
*src = ZPROP_SRC_NONE;
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 50f48fd793..9e5641ec46 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
*/
@@ -79,6 +80,7 @@ struct libzfs_handle {
libzfs_fru_t **libzfs_fru_hash;
libzfs_fru_t *libzfs_fru_list;
char libzfs_chassis_id[256];
+ boolean_t libzfs_cachedprops;
boolean_t libzfs_prop_debug;
};
@@ -151,6 +153,7 @@ int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
size_t *);
zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
zfs_handle_t *make_dataset_simple_handle_zc(zfs_handle_t *, zfs_cmd_t *);
+int libzfs_cmd_set_cachedprops(libzfs_handle_t *, zfs_cmd_t *);
int zprop_parse_value(libzfs_handle_t *, nvpair_t *, int, zfs_type_t,
nvlist_t *, char **, uint64_t *, const char *);
diff --git a/usr/src/lib/libzfs/common/libzfs_iter.c b/usr/src/lib/libzfs/common/libzfs_iter.c
index f5ac68fc94..11ff3e2fd7 100644
--- a/usr/src/lib/libzfs/common/libzfs_iter.c
+++ b/usr/src/lib/libzfs/common/libzfs_iter.c
@@ -24,6 +24,7 @@
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <stdio.h>
@@ -111,6 +112,10 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
return (0);
+ if (zhp->zfs_hdl->libzfs_cachedprops &&
+ libzfs_cmd_set_cachedprops(zhp->zfs_hdl, &zc) != 0)
+ return (-1);
+
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1);
@@ -121,9 +126,8 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
* that the pool has since been removed.
*/
if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
- &zc)) == NULL) {
+ &zc)) == NULL)
continue;
- }
if ((ret = func(nzhp, data)) != 0) {
zcmd_free_nvlists(&zc);
@@ -149,10 +153,17 @@ zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
zhp->zfs_type == ZFS_TYPE_BOOKMARK)
return (0);
+
+ if (zhp->zfs_hdl->libzfs_cachedprops &&
+ libzfs_cmd_set_cachedprops(zhp->zfs_hdl, &zc) != 0)
+ return (-1);
+
zc.zc_simple = simple;
+
if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
return (-1);
+
while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
&zc)) == 0) {
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index 45b095f40a..9fd37825a3 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -24,6 +24,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright 2017 Joyent, Inc.
* Copyright 2017 RackTop Systems.
*/
@@ -664,8 +665,14 @@ _zfs_init_libshare(void)
static int
zfs_init_libshare_impl(libzfs_handle_t *zhandle, int service, void *arg)
{
+ /*
+ * libshare is either not installed or we're in a branded zone. The
+ * rest of the wrapper functions around the libshare calls already
+ * handle NULL function pointers, but we don't want the callers of
+ * zfs_init_libshare() to fail prematurely if libshare is not available.
+ */
if (_sa_init == NULL)
- return (SA_CONFIG_ERR);
+ return (SA_OK);
/*
* Attempt to refresh libshare. This is necessary if there was a cache
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 9786f2b299..d9843f316f 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -365,6 +365,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
default:
(void) snprintf(buf, len, "%llu", intval);
}
+
break;
case PROP_TYPE_INDEX:
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 9760fdf35d..365ece14e0 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -84,6 +84,9 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
case EZFS_PROPSPACE:
return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
+ case EZFS_PROPCACHED:
+ return (dgettext(TEXT_DOMAIN, "property unavailable since "
+ "cachedprops flag set"));
case EZFS_BADTYPE:
return (dgettext(TEXT_DOMAIN, "operation not applicable to "
"datasets of this type"));
@@ -612,6 +615,42 @@ libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
hdl->libzfs_printerr = printerr;
}
+/*
+ * Set the value of the cachedprops flag. If the cachedprops flag is set,
+ * operations which get ZFS properties will only retrieve a property if the
+ * property is cached somewhere in memory.
+ *
+ * Consumers of libzfs should take care when setting this flag, as they will
+ * prevent themselves from listing the full set of ZFS properties.
+ *
+ * ZFS properties which always require disk I/O are ZPL properties (utf8only,
+ * normalization, etc.) and the volsize and volblocksize properties for volumes.
+ */
+void
+libzfs_set_cachedprops(libzfs_handle_t *hdl, boolean_t cachedprops)
+{
+ hdl->libzfs_cachedprops = cachedprops;
+}
+
+/*
+ * Adds a src nvlist to a zfs_cmd_t which specifies that only cached (i.e., will
+ * not require a disk access) properties should be retrieved.
+ */
+int
+libzfs_cmd_set_cachedprops(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+ nvlist_t *nvl;
+ int ret;
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_boolean_value(nvl, "cachedpropsonly", B_TRUE) != 0)
+ return (no_memory(hdl));
+
+ ret = zcmd_write_src_nvlist(hdl, zc, nvl);
+ nvlist_free(nvl);
+ return (ret);
+}
+
libzfs_handle_t *
libzfs_init(void)
{
@@ -647,6 +686,7 @@ libzfs_init(void)
zpool_feature_init();
libzfs_mnttab_init(hdl);
+ hdl->libzfs_cachedprops = B_FALSE;
if (getenv("ZFS_PROP_DEBUG") != NULL) {
hdl->libzfs_prop_debug = B_TRUE;
}
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 7fa722a532..8feff24f87 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -22,6 +22,7 @@
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
# Copyright 2016 Nexenta Systems, Inc.
#
@@ -63,6 +64,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
libzfs_init;
libzfs_mnttab_cache;
libzfs_print_on_error;
+ libzfs_set_cachedprops;
spa_feature_table;
zfs_allocatable_devs;
zfs_asprintf;
@@ -110,6 +112,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_path_to_zhandle;
zfs_promote;
zfs_prop_align_right;
+ zfs_prop_cacheable;
zfs_prop_column_name;
zfs_prop_default_numeric;
zfs_prop_default_string;
diff --git a/usr/src/lib/libzonecfg/Makefile.com b/usr/src/lib/libzonecfg/Makefile.com
index 0bee2fc908..6bec7141cb 100644
--- a/usr/src/lib/libzonecfg/Makefile.com
+++ b/usr/src/lib/libzonecfg/Makefile.com
@@ -20,11 +20,14 @@
#
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
LIBRARY= libzonecfg.a
VERS= .1
-OBJECTS= libzonecfg.o getzoneent.o scratchops.o
+LIB_OBJS= libzonecfg.o getzoneent.o scratchops.o
+XML_OBJS= os_dtd.o
+OBJECTS= $(LIB_OBJS) $(XML_OBJS)
include ../../Makefile.lib
@@ -35,15 +38,27 @@ LDLIBS += -lc -lsocket -lnsl -luuid -lnvpair -lsysevent -lsec -lbrand \
$(DYNLIB) := LDLIBS += -lxml2
SRCDIR = ../common
+
+XMLDIR = $(SRC)/lib/xml
+SRCS = \
+ $(LIB_OBJS:%.o=$(SRCDIR)/%.c) \
+ $(XML_OBJS:%.o=$(XMLDIR)/%.c) \
+
CPPFLAGS += -I$(ADJUNCT_PROTO)/usr/include/libxml2 -I$(SRCDIR) -D_REENTRANT
CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-parentheses
$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
+CPPFLAGS += -I$(XMLDIR)
+
.KEEP_STATE:
all: $(LIBS)
lint: lintcheck
+pics/%.o: $(XMLDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
include ../../Makefile.targ
diff --git a/usr/src/lib/libzonecfg/common/getzoneent.c b/usr/src/lib/libzonecfg/common/getzoneent.c
index 8155f7272a..c9f1c12bcf 100644
--- a/usr/src/lib/libzonecfg/common/getzoneent.c
+++ b/usr/src/lib/libzonecfg/common/getzoneent.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
@@ -127,6 +128,8 @@ getzoneent_private(FILE *cookie)
/* skip comment lines */
continue;
}
+
+ /* zonename */
p = gettok(&cp);
if (*p == '\0' || strlen(p) >= ZONENAME_MAX) {
/*
@@ -136,6 +139,7 @@ getzoneent_private(FILE *cookie)
}
(void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
+ /* state */
p = gettok(&cp);
if (*p == '\0') {
/* state field should not be empty */
@@ -152,6 +156,7 @@ getzoneent_private(FILE *cookie)
continue;
}
+ /* zonepath */
p = gettok(&cp);
if (strlen(p) >= MAXPATHLEN) {
/* very long paths are not allowed */
@@ -159,10 +164,35 @@ getzoneent_private(FILE *cookie)
}
(void) strlcpy(ze->zone_path, p, MAXPATHLEN);
+ /* uuid */
p = gettok(&cp);
if (uuid_parse(p, ze->zone_uuid) == -1)
uuid_clear(ze->zone_uuid);
+ /* brand [optional] */
+ p = gettok(&cp);
+ if (strlen(p) >= MAXNAMELEN) {
+ /* very long names are not allowed */
+ continue;
+ }
+ (void) strlcpy(ze->zone_brand, p, MAXNAMELEN);
+
+ /* IP type [optional] */
+ p = gettok(&cp);
+ if (strlen(p) >= MAXNAMELEN) {
+ /* very long names are not allowed */
+ continue;
+ }
+ ze->zone_iptype = ZS_SHARED;
+ if (*p == 'e') {
+ ze->zone_iptype = ZS_EXCLUSIVE;
+ }
+
+ /* debug ID [optional] */
+ p = gettok(&cp);
+ if (*p != '\0')
+ ze->zone_did = atoi(p);
+
break;
}
@@ -170,10 +200,32 @@ getzoneent_private(FILE *cookie)
}
static boolean_t
-get_index_path(char *path)
+path_common(char *path, size_t path_size, const char *stem)
{
- return (snprintf(path, MAXPATHLEN, "%s%s", zonecfg_root,
- ZONE_INDEX_FILE) < MAXPATHLEN);
+ const char *native_root = zone_get_nroot();
+
+ if (native_root == NULL || zonecfg_in_alt_root()) {
+ /*
+ * Do not prepend the native system root (e.g. "/native") if an
+ * alternative configuration root has been selected.
+ */
+ native_root = "";
+ }
+
+ return (snprintf(path, path_size, "%s%s%s", native_root, zonecfg_root,
+ stem) < path_size);
+}
+
+static boolean_t
+get_index_path(char *path, size_t path_size)
+{
+ return (path_common(path, path_size, ZONE_INDEX_FILE));
+}
+
+static boolean_t
+get_temp_path(char *path, size_t path_size)
+{
+ return (path_common(path, path_size, _PATH_TMPFILE));
}
FILE *
@@ -181,7 +233,7 @@ setzoneent(void)
{
char path[MAXPATHLEN];
- if (!get_index_path(path)) {
+ if (!get_index_path(path, sizeof (path))) {
errno = EINVAL;
return (NULL);
}
@@ -202,8 +254,7 @@ lock_index_file(void)
struct flock lock;
char path[MAXPATHLEN];
- if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
- ZONE_INDEX_LOCK_DIR) >= sizeof (path))
+ if (!path_common(path, sizeof (path), ZONE_INDEX_LOCK_DIR))
return (-1);
if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST)
return (-1);
@@ -269,14 +320,17 @@ int
putzoneent(struct zoneent *ze, zoneent_op_t operation)
{
FILE *index_file, *tmp_file;
- char *tmp_file_name, buf[MAX_INDEX_LEN];
+ char buf[MAX_INDEX_LEN];
int tmp_file_desc, lock_fd, err;
boolean_t exist, need_quotes;
- char *cp;
+ char *cp, *tmpp;
+ char tmp_path[MAXPATHLEN];
char path[MAXPATHLEN];
char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
- size_t tlen, namelen;
- const char *zone_name, *zone_state, *zone_path, *zone_uuid;
+ size_t namelen;
+ const char *zone_name, *zone_state, *zone_path, *zone_uuid,
+ *zone_brand = "", *zone_iptype;
+ zoneid_t zone_did;
assert(ze != NULL);
@@ -299,20 +353,14 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
if ((lock_fd = lock_index_file()) == -1)
return (Z_LOCKING_FILE);
- /* using sizeof gives us room for the terminating NUL byte as well */
- tlen = sizeof (_PATH_TMPFILE) + strlen(zonecfg_root);
- tmp_file_name = malloc(tlen);
- if (tmp_file_name == NULL) {
+ if (!get_temp_path(tmp_path, sizeof (tmp_path))) {
(void) unlock_index_file(lock_fd);
return (Z_NOMEM);
}
- (void) snprintf(tmp_file_name, tlen, "%s%s", zonecfg_root,
- _PATH_TMPFILE);
- tmp_file_desc = mkstemp(tmp_file_name);
+ tmp_file_desc = mkstemp(tmp_path);
if (tmp_file_desc == -1) {
- (void) unlink(tmp_file_name);
- free(tmp_file_name);
+ (void) unlink(tmp_path);
(void) unlock_index_file(lock_fd);
return (Z_TEMP_FILE);
}
@@ -323,7 +371,7 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
err = Z_MISC_FS;
goto error;
}
- if (!get_index_path(path)) {
+ if (!get_index_path(path, sizeof (path))) {
err = Z_MISC_FS;
goto error;
}
@@ -335,6 +383,9 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
exist = B_FALSE;
zone_name = ze->zone_name;
namelen = strlen(zone_name);
+ zone_brand = ze->zone_brand;
+ zone_iptype = (ze->zone_iptype == ZS_SHARED ? "sh" : "ex");
+ zone_did = ze->zone_did;
for (;;) {
if (fgets(buf, sizeof (buf), index_file) == NULL) {
if (operation == PZE_ADD && !exist) {
@@ -389,6 +440,11 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
}
zone_path = gettok(&cp);
zone_uuid = gettok(&cp);
+ zone_brand = gettok(&cp);
+ zone_iptype = gettok(&cp);
+ tmpp = gettok(&cp);
+ if (*tmpp != '\0')
+ zone_did = atoi(tmpp);
switch (operation) {
case PZE_ADD:
@@ -403,14 +459,6 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
*/
if (ze->zone_state >= 0) {
zone_state = zone_state_str(ze->zone_state);
-
- /*
- * If the caller is uninstalling this zone,
- * then wipe out the uuid. The zone's contents
- * are no longer known.
- */
- if (ze->zone_state < ZONE_STATE_INSTALLED)
- zone_uuid = "";
}
/* If a new name is supplied, use it. */
@@ -419,6 +467,27 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
if (ze->zone_path[0] != '\0')
zone_path = ze->zone_path;
+
+ /* If new UUID provided, replace it */
+ if (!uuid_is_null(ze->zone_uuid)) {
+ uuid_unparse(ze->zone_uuid, uuidstr);
+ zone_uuid = uuidstr;
+ }
+
+ /* If a brand is supplied, use it. */
+ if (ze->zone_brand[0] != '\0') {
+ zone_brand = ze->zone_brand;
+
+ /*
+ * Since the brand, iptype and did are optional,
+ * we we only reset the iptype and did if the
+ * brand is provided.
+ */
+ zone_iptype = (ze->zone_iptype == ZS_SHARED ?
+ "sh" : "ex");
+ zone_did = ze->zone_did;
+ }
+
break;
case PZE_REMOVE:
@@ -450,9 +519,17 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
* method for escaping them.
*/
need_quotes = (strchr(zone_path, ':') != NULL);
- (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
- zone_state, need_quotes ? "\"" : "", zone_path,
- need_quotes ? "\"" : "", zone_uuid);
+
+ if (*zone_brand != '\0') {
+ (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s:%s:%s:%d\n",
+ zone_name, zone_state, need_quotes ? "\"" : "",
+ zone_path, need_quotes ? "\"" : "", zone_uuid,
+ zone_brand, zone_iptype, zone_did);
+ } else {
+ (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
+ zone_state, need_quotes ? "\"" : "", zone_path,
+ need_quotes ? "\"" : "", zone_uuid);
+ }
exist = B_TRUE;
}
@@ -464,11 +541,10 @@ putzoneent(struct zoneent *ze, zoneent_op_t operation)
goto error;
}
tmp_file = NULL;
- if (rename(tmp_file_name, path) == -1) {
+ if (rename(tmp_path, path) == -1) {
err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
goto error;
}
- free(tmp_file_name);
if (unlock_index_file(lock_fd) != Z_OK)
return (Z_UNLOCKING_FILE);
return (Z_OK);
@@ -478,8 +554,7 @@ error:
(void) fclose(index_file);
if (tmp_file != NULL)
(void) fclose(tmp_file);
- (void) unlink(tmp_file_name);
- free(tmp_file_name);
+ (void) unlink(tmp_path);
(void) unlock_index_file(lock_fd);
return (err);
}
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index 29327525e2..c524901d48 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -22,6 +22,7 @@
/*
* Copyright 2014 Gary Mills
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent Inc.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
@@ -59,6 +60,8 @@
#include <secdb.h>
#include <user_attr.h>
#include <prof_attr.h>
+#include <sys/debug.h>
+#include <os_dtd.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -79,6 +82,8 @@
#define ZONE_EVENT_PING_SUBCLASS "ping"
#define ZONE_EVENT_PING_PUBLISHER "solaris"
+#define DEBUGID_FILE "/etc/zones/did.txt"
+
/* Hard-code the DTD element/attribute/entity names just once, here. */
#define DTD_ELEM_ATTR (const xmlChar *) "attr"
#define DTD_ELEM_COMMENT (const xmlChar *) "comment"
@@ -86,6 +91,7 @@
#define DTD_ELEM_FS (const xmlChar *) "filesystem"
#define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
#define DTD_ELEM_NET (const xmlChar *) "network"
+#define DTD_ELEM_NETATTR (const xmlChar *) "net-attr"
#define DTD_ELEM_RCTL (const xmlChar *) "rctl"
#define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
#define DTD_ELEM_ZONE (const xmlChar *) "zone"
@@ -106,10 +112,12 @@
#define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
#define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
#define DTD_ATTR_DIR (const xmlChar *) "directory"
+#define DTD_ATTR_GNIC (const xmlChar *) "global-nic"
#define DTD_ATTR_LIMIT (const xmlChar *) "limit"
#define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv"
#define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs"
#define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class"
+#define DTD_ATTR_MAC (const xmlChar *) "mac-addr"
#define DTD_ATTR_MATCH (const xmlChar *) "match"
#define DTD_ATTR_NAME (const xmlChar *) "name"
#define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
@@ -119,6 +127,7 @@
#define DTD_ATTR_SPECIAL (const xmlChar *) "special"
#define DTD_ATTR_TYPE (const xmlChar *) "type"
#define DTD_ATTR_VALUE (const xmlChar *) "value"
+#define DTD_ATTR_VLANID (const xmlChar *) "vlan-id"
#define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
#define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
#define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
@@ -131,6 +140,7 @@
#define DTD_ATTR_MODE (const xmlChar *) "mode"
#define DTD_ATTR_ACL (const xmlChar *) "acl"
#define DTD_ATTR_BRAND (const xmlChar *) "brand"
+#define DTD_ATTR_DID (const xmlChar *) "debugid"
#define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
#define DTD_ATTR_USER (const xmlChar *) "user"
#define DTD_ATTR_AUTHS (const xmlChar *) "auths"
@@ -181,9 +191,12 @@ static struct alias {
{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
+ {ALIAS_MAXPHYSMEM, "zone.max-physical-memory", "privileged", "deny",
+ 1048576},
{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
+ {ALIAS_ZFSPRI, "zone.zfs-io-priority", "privileged", "none", 0},
{NULL, NULL, NULL, NULL, 0}
};
@@ -231,6 +244,8 @@ static int zone_lock_cnt = 0;
static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
+static void zonecfg_notify_delete(const char *);
+
char *zonecfg_root = "";
/*
@@ -274,17 +289,35 @@ zonecfg_in_alt_root(void)
*/
static boolean_t
-config_file_path(const char *zonename, char *answer)
+file_path_common(const char *zonename, const char *subdir, const char *stem,
+ char *answer, size_t answer_size)
{
- return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
- ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
+ const char *native_root = zone_get_nroot();
+
+ if (native_root == NULL || zonecfg_in_alt_root()) {
+ /*
+ * Do not prepend the native system root (e.g. "/native") if an
+ * alternative configuration root has been selected.
+ */
+ native_root = "";
+ }
+
+ return (snprintf(answer, answer_size, "%s%s%s/%s.%s", native_root,
+ zonecfg_root, subdir, zonename, stem) < answer_size);
}
static boolean_t
-snap_file_path(const char *zonename, char *answer)
+config_file_path(const char *zonename, char *answer, size_t answer_size)
{
- return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
- zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
+ return (file_path_common(zonename, ZONE_CONFIG_ROOT, "xml", answer,
+ answer_size));
+}
+
+static boolean_t
+snap_file_path(const char *zonename, char *answer, size_t answer_size)
+{
+ return (file_path_common(zonename, ZONE_SNAPSHOT_ROOT, "snapshot.xml",
+ answer, answer_size));
}
/*ARGSUSED*/
@@ -355,7 +388,7 @@ zonecfg_destroy(const char *zonename, boolean_t force)
int err, state_err;
zone_state_t state;
- if (!config_file_path(zonename, path))
+ if (!config_file_path(zonename, path, sizeof (path)))
return (Z_MISC_FS);
state_err = zone_get_state((char *)zonename, &state);
@@ -402,8 +435,10 @@ zonecfg_destroy(const char *zonename, boolean_t force)
* Treat failure to find the XML file silently, since, well, it's
* gone, and with the index file cleaned up, we're done.
*/
- if (err == Z_OK || err == Z_NO_ZONE)
+ if (err == Z_OK || err == Z_NO_ZONE) {
+ zonecfg_notify_delete(zonename);
return (Z_OK);
+ }
return (err);
}
@@ -412,7 +447,7 @@ zonecfg_destroy_snapshot(const char *zonename)
{
char path[MAXPATHLEN];
- if (!snap_file_path(zonename, path))
+ if (!snap_file_path(zonename, path, sizeof (path)))
return (Z_MISC_FS);
return (zonecfg_destroy_impl(path));
}
@@ -579,9 +614,8 @@ static int
zonecfg_get_handle_impl(const char *zonename, const char *filename,
zone_dochandle_t handle)
{
- xmlValidCtxtPtr cvp;
struct stat statbuf;
- int valid;
+ boolean_t valid;
if (zonename == NULL)
return (Z_NO_ZONE);
@@ -592,14 +626,13 @@ zonecfg_get_handle_impl(const char *zonename, const char *filename,
return (Z_INVALID_DOCUMENT);
return (Z_NO_ZONE);
}
- if ((cvp = xmlNewValidCtxt()) == NULL)
+
+ if (os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid) != 0) {
return (Z_NOMEM);
- cvp->error = zonecfg_error_func;
- cvp->warning = zonecfg_error_func;
- valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
- xmlFreeValidCtxt(cvp);
- if (valid == 0)
+ }
+ if (!valid) {
return (Z_INVALID_DOCUMENT);
+ }
/* delete any comments such as inherited Sun copyright / ident str */
stripcomments(handle);
@@ -611,7 +644,7 @@ zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
{
char path[MAXPATHLEN];
- if (!config_file_path(zonename, path))
+ if (!config_file_path(zonename, path, sizeof (path)))
return (Z_MISC_FS);
handle->zone_dh_newzone = B_FALSE;
@@ -655,7 +688,7 @@ zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
{
char path[MAXPATHLEN];
- if (!snap_file_path(zonename, path))
+ if (!snap_file_path(zonename, path, sizeof (path)))
return (Z_MISC_FS);
handle->zone_dh_newzone = B_FALSE;
return (zonecfg_get_handle_impl(zonename, path, handle));
@@ -668,7 +701,7 @@ zonecfg_get_template_handle(const char *template, const char *zonename,
char path[MAXPATHLEN];
int err;
- if (!config_file_path(template, path))
+ if (!config_file_path(template, path, sizeof (path)))
return (Z_MISC_FS);
if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
@@ -702,21 +735,19 @@ int
zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
zone_dochandle_t rem_handle)
{
- xmlValidCtxtPtr cvp;
- int valid;
+ boolean_t valid;
/* load the manifest into the handle for the remote system */
if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
return (Z_INVALID_DOCUMENT);
}
- if ((cvp = xmlNewValidCtxt()) == NULL)
+
+ if (os_dtd_validate(rem_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
return (Z_NOMEM);
- cvp->error = zonecfg_error_func;
- cvp->warning = zonecfg_error_func;
- valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
- xmlFreeValidCtxt(cvp);
- if (valid == 0)
+ }
+ if (!valid) {
return (Z_INVALID_DOCUMENT);
+ }
/* delete any comments such as inherited Sun copyright / ident str */
stripcomments(rem_handle);
@@ -737,14 +768,12 @@ zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
* We need to re-run xmlValidateDocument on local_handle to properly
* update the in-core representation of the configuration.
*/
- if ((cvp = xmlNewValidCtxt()) == NULL)
+ if (os_dtd_validate(local_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
return (Z_NOMEM);
- cvp->error = zonecfg_error_func;
- cvp->warning = zonecfg_error_func;
- valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
- xmlFreeValidCtxt(cvp);
- if (valid == 0)
+ }
+ if (!valid) {
return (Z_INVALID_DOCUMENT);
+ }
strip_sw_inv(local_handle);
@@ -1106,7 +1135,7 @@ zonecfg_set_sched(zone_dochandle_t handle, char *sched)
* In general, the operation of this function should succeed or fail as
* a unit.
*/
-int
+static int
zonecfg_refresh_index_file(zone_dochandle_t handle)
{
char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
@@ -1128,6 +1157,15 @@ zonecfg_refresh_index_file(zone_dochandle_t handle)
(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
sizeof (ze.zone_path));
+ if ((err = zonecfg_get_brand(handle, ze.zone_brand,
+ sizeof (ze.zone_brand))) != 0)
+ return (err);
+
+ if ((err = zonecfg_get_iptype(handle, &ze.zone_iptype)) != Z_OK)
+ return (err);
+
+ ze.zone_did = zonecfg_get_did(handle);
+
if (is_renaming(handle)) {
opcode = PZE_MODIFY;
(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
@@ -1198,9 +1236,9 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename)
{
char tmpfile[MAXPATHLEN];
char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
- int tmpfd, err, valid;
- xmlValidCtxt cvp = { NULL };
+ int tmpfd, err;
boolean_t backup;
+ boolean_t valid;
(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
(void) dirname(tmpfile);
@@ -1213,16 +1251,13 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename)
}
(void) close(tmpfd);
- cvp.error = zonecfg_error_func;
- cvp.warning = zonecfg_error_func;
-
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
- valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
- assert(valid != 0);
+ VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+ VERIFY(valid == B_TRUE);
if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
goto err;
@@ -1277,7 +1312,6 @@ zonecfg_save_impl(zone_dochandle_t handle, char *filename)
/*
* Try to restore from our backup.
*/
- (void) unlink(filename);
(void) rename(bakfile, filename);
} else {
/*
@@ -1320,7 +1354,7 @@ zonecfg_save(zone_dochandle_t handle)
if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
return (err);
- if (!config_file_path(zname, path))
+ if (!config_file_path(zname, path, sizeof (path)))
return (Z_MISC_FS);
addcomment(handle, "\n DO NOT EDIT THIS "
@@ -1341,8 +1375,10 @@ zonecfg_save(zone_dochandle_t handle)
handle->zone_dh_newzone = B_FALSE;
if (is_renaming(handle)) {
- if (config_file_path(handle->zone_dh_delete_name, delpath))
+ if (config_file_path(handle->zone_dh_delete_name, delpath,
+ sizeof (delpath))) {
(void) unlink(delpath);
+ }
handle->zone_dh_delete_name[0] = '\0';
}
@@ -1352,23 +1388,18 @@ zonecfg_save(zone_dochandle_t handle)
int
zonecfg_verify_save(zone_dochandle_t handle, char *filename)
{
- int valid;
-
- xmlValidCtxt cvp = { NULL };
+ boolean_t valid;
if (zonecfg_check_handle(handle) != Z_OK)
return (Z_BAD_HANDLE);
- cvp.error = zonecfg_error_func;
- cvp.warning = zonecfg_error_func;
-
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
- valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
- assert(valid != 0);
+ VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+ VERIFY(valid == B_TRUE);
if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
return (Z_SAVING_FILE);
@@ -1382,9 +1413,8 @@ zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
char zname[ZONENAME_MAX];
char path[MAXPATHLEN];
char migpath[MAXPATHLEN];
- xmlValidCtxt cvp = { NULL };
int err = Z_SAVING_FILE;
- int valid;
+ boolean_t valid;
if (zonecfg_check_handle(handle) != Z_OK)
return (Z_BAD_HANDLE);
@@ -1411,16 +1441,13 @@ zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
addcomment(handle, "\n DO NOT EDIT THIS FILE. "
"Use zonecfg(1M) and zoneadm(1M) attach.\n");
- cvp.error = zonecfg_error_func;
- cvp.warning = zonecfg_error_func;
-
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
- valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
- assert(valid != 0);
+ VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+ VERIFY(valid == B_TRUE);
if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
return (Z_SAVING_FILE);
@@ -1481,6 +1508,56 @@ zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
}
}
+static void
+zonecfg_notify_conf_change(const char *zname, char *os, char *ns)
+{
+ evchan_t *ze_chan;
+ struct timeval now;
+ uint64_t t;
+ nvlist_t *nvl = NULL;
+
+ if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &ze_chan, 0) != 0)
+ return;
+
+ /* Current time since Jan 1 1970 but consumers expect NS */
+ gettimeofday(&now, NULL);
+ t = (now.tv_sec * NANOSEC) + (now.tv_usec * 1000);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0 &&
+ nvlist_add_string(nvl, ZONE_CB_NAME, zname) == 0 &&
+ nvlist_add_string(nvl, ZONE_CB_NEWSTATE, ns) == 0 &&
+ nvlist_add_string(nvl, ZONE_CB_OLDSTATE, os) == 0 &&
+ nvlist_add_int32(nvl, ZONE_CB_ZONEID, -1) == 0 &&
+ nvlist_add_uint64(nvl, ZONE_CB_TIMESTAMP, t) == 0) {
+ (void) sysevent_evc_publish(ze_chan, ZONE_EVENT_STATUS_CLASS,
+ ZONE_EVENT_STATUS_SUBCLASS, "sun.com", "zonecfg", nvl,
+ EVCH_SLEEP);
+ }
+
+ nvlist_free(nvl);
+ (void) sysevent_evc_unbind(ze_chan);
+}
+
+void
+zonecfg_notify_create(zone_dochandle_t handle)
+{
+ char zname[ZONENAME_MAX];
+
+ if (zonecfg_check_handle(handle) != Z_OK)
+ return;
+
+ if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
+ return;
+
+ zonecfg_notify_conf_change(zname, "", ZONE_STATE_STR_CONFIGURED);
+}
+
+static void
+zonecfg_notify_delete(const char *zname)
+{
+ zonecfg_notify_conf_change(zname, ZONE_STATE_STR_CONFIGURED, "");
+}
+
/*
* Special case: if access(2) fails with ENOENT, then try again using
* ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
@@ -1493,7 +1570,7 @@ zonecfg_access(const char *zonename, int amode)
{
char path[MAXPATHLEN];
- if (!config_file_path(zonename, path))
+ if (!config_file_path(zonename, path, sizeof (path)))
return (Z_INVAL);
if (access(path, amode) == 0)
return (Z_OK);
@@ -1558,7 +1635,7 @@ zonecfg_create_snapshot(const char *zonename)
goto out;
}
- if (!snap_file_path(zonename, path)) {
+ if (!snap_file_path(zonename, path, sizeof (path))) {
error = Z_MISC_FS;
goto out;
}
@@ -2071,6 +2148,32 @@ zonecfg_ifname_exists(sa_family_t af, char *ifname)
}
/*
+ * Turn an addr that looks like f:2:0:44:5:6C into 0f:02:00:44:05:6c
+ * We're expecting a dst of at least MAXMACADDRLEN size here.
+ */
+static void
+normalize_mac_addr(char *dst, const char *src, int len)
+{
+ char *p, *e, *sep = "";
+ long n;
+ char buf[MAXMACADDRLEN], tmp[4];
+
+ *dst = '\0';
+ (void) strlcpy(buf, src, sizeof (buf));
+ p = strtok(buf, ":");
+ while (p != NULL) {
+ n = strtol(p, &e, 16);
+ if (*e != NULL || n > 0xff)
+ return;
+ (void) snprintf(tmp, sizeof (tmp), "%s%02x", sep, n);
+ (void) strlcat(dst, tmp, len);
+
+ sep = ":";
+ p = strtok(NULL, ":");
+ }
+}
+
+/*
* Determines whether there is a net resource with the physical interface, IP
* address, and default router specified by 'tabptr' in the zone configuration
* to which 'handle' refers. 'tabptr' must have an interface, an address, a
@@ -2089,13 +2192,18 @@ zonecfg_ifname_exists(sa_family_t af, char *ifname)
int
zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
{
- xmlNodePtr cur;
+ xmlNodePtr cur, val;
xmlNodePtr firstmatch;
int err;
char address[INET6_ADDRSTRLEN];
char physical[LIFNAMSIZ];
+ char mac[MAXMACADDRLEN];
+ char norm_mac[MAXMACADDRLEN];
+ char gnic[LIFNAMSIZ];
size_t addrspec; /* nonzero if tabptr has IP addr */
size_t physspec; /* nonzero if tabptr has interface */
+ size_t macspec; /* nonzero if tabptr has mac addr */
+ size_t gnicspec; /* nonzero if tabptr has gnic */
size_t defrouterspec; /* nonzero if tabptr has def. router */
size_t allowed_addrspec;
zone_iptype_t iptype;
@@ -2107,17 +2215,20 @@ zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
* Determine the fields that will be searched. There must be at least
* one.
*
- * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
+ * zone_nwif_address, zone_nwif_physical, zone_nwif_defrouter,
+ * zone_nwif_mac, zone_nwif_vlan_id and zone_nwif_gnic are
* arrays, so no NULL checks are necessary.
*/
addrspec = strlen(tabptr->zone_nwif_address);
physspec = strlen(tabptr->zone_nwif_physical);
+ macspec = strlen(tabptr->zone_nwif_mac);
+ gnicspec = strlen(tabptr->zone_nwif_gnic);
defrouterspec = strlen(tabptr->zone_nwif_defrouter);
allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
if (addrspec != 0 && allowed_addrspec != 0)
return (Z_INVAL); /* can't specify both */
if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
- allowed_addrspec == 0)
+ allowed_addrspec == 0 && macspec == 0 && gnicspec == 0)
return (Z_INSUFFICIENT_SPEC);
if ((err = operation_prep(handle)) != Z_OK)
@@ -2144,6 +2255,19 @@ zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
physical, sizeof (physical)) != Z_OK ||
strcmp(tabptr->zone_nwif_physical, physical) != 0))
continue;
+ if (iptype == ZS_EXCLUSIVE && macspec != 0) {
+ if (fetchprop(cur, DTD_ATTR_MAC, mac, sizeof (mac)) !=
+ Z_OK)
+ continue;
+ normalize_mac_addr(norm_mac, mac, sizeof (norm_mac));
+ if (strcmp(tabptr->zone_nwif_mac, norm_mac) != 0)
+ continue;
+ }
+ if (iptype == ZS_EXCLUSIVE && gnicspec != 0 &&
+ (fetchprop(cur, DTD_ATTR_GNIC, gnic,
+ sizeof (gnic)) != Z_OK ||
+ strcmp(tabptr->zone_nwif_gnic, gnic) != 0))
+ continue;
if (iptype == ZS_SHARED && addrspec != 0 &&
(fetchprop(cur, DTD_ATTR_ADDRESS, address,
sizeof (address)) != Z_OK ||
@@ -2186,6 +2310,21 @@ zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
return (err);
if (iptype == ZS_EXCLUSIVE &&
+ (err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
+ sizeof (tabptr->zone_nwif_mac))) != Z_OK)
+ return (err);
+
+ if (iptype == ZS_EXCLUSIVE &&
+ (err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
+ sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK)
+ return (err);
+
+ if (iptype == ZS_EXCLUSIVE &&
+ (err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
+ sizeof (tabptr->zone_nwif_gnic))) != Z_OK)
+ return (err);
+
+ if (iptype == ZS_EXCLUSIVE &&
(err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
tabptr->zone_nwif_allowed_address,
sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
@@ -2196,13 +2335,40 @@ zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
return (err);
+ tabptr->zone_nwif_attrp = NULL;
+ for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+ struct zone_res_attrtab *valptr;
+
+ valptr = (struct zone_res_attrtab *)malloc(
+ sizeof (struct zone_res_attrtab));
+ if (valptr == NULL)
+ return (Z_NOMEM);
+
+ valptr->zone_res_attr_name[0] =
+ valptr->zone_res_attr_value[0] = '\0';
+ if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
+ != Z_OK) {
+ free(valptr);
+ break;
+ }
+
+ if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+ sizeof (valptr->zone_res_attr_name)) != Z_OK))
+ break;
+ if ((fetchprop(val, DTD_ATTR_VALUE,
+ valptr->zone_res_attr_value,
+ sizeof (valptr->zone_res_attr_value)) != Z_OK))
+ break;
+ }
+
return (Z_OK);
}
static int
zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
{
- xmlNodePtr newnode, cur = handle->zone_dh_cur;
+ xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
+ struct zone_res_attrtab *valptr;
int err;
newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
@@ -2218,13 +2384,40 @@ zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
tabptr->zone_nwif_physical)) != Z_OK)
return (err);
/*
- * Do not add this property when it is not set, for backwards
- * compatibility and because it is optional.
+ * Do not add these properties when they are not set, for backwards
+ * compatibility and because they are optional.
*/
if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
((err = newprop(newnode, DTD_ATTR_DEFROUTER,
tabptr->zone_nwif_defrouter)) != Z_OK))
return (err);
+ if (strlen(tabptr->zone_nwif_mac) > 0 &&
+ (err = newprop(newnode, DTD_ATTR_MAC,
+ tabptr->zone_nwif_mac)) != Z_OK)
+ return (err);
+ if (strlen(tabptr->zone_nwif_vlan_id) > 0 &&
+ (err = newprop(newnode, DTD_ATTR_VLANID,
+ tabptr->zone_nwif_vlan_id)) != Z_OK)
+ return (err);
+ if (strlen(tabptr->zone_nwif_gnic) > 0 &&
+ (err = newprop(newnode, DTD_ATTR_GNIC,
+ tabptr->zone_nwif_gnic)) != Z_OK)
+ return (err);
+
+ for (valptr = tabptr->zone_nwif_attrp; valptr != NULL;
+ valptr = valptr->zone_res_attr_next) {
+ valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
+ NULL);
+ err = newprop(valnode, DTD_ATTR_NAME,
+ valptr->zone_res_attr_name);
+ if (err != Z_OK)
+ return (err);
+ err = newprop(valnode, DTD_ATTR_VALUE,
+ valptr->zone_res_attr_value);
+ if (err != Z_OK)
+ return (err);
+ }
+
return (Z_OK);
}
@@ -2249,7 +2442,8 @@ static int
zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
{
xmlNodePtr cur = handle->zone_dh_cur;
- boolean_t addr_match, phys_match, allowed_addr_match;
+ boolean_t addr_match, phys_match, allowed_addr_match, mac_match,
+ gnic_match;
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (xmlStrcmp(cur->name, DTD_ELEM_NET))
@@ -2261,8 +2455,13 @@ zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
tabptr->zone_nwif_allowed_address);
phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
tabptr->zone_nwif_physical);
+ mac_match = match_prop(cur, DTD_ATTR_MAC,
+ tabptr->zone_nwif_mac);
+ gnic_match = match_prop(cur, DTD_ATTR_GNIC,
+ tabptr->zone_nwif_gnic);
- if (addr_match && allowed_addr_match && phys_match) {
+ if (((addr_match && allowed_addr_match) || mac_match ||
+ gnic_match) && phys_match) {
xmlUnlinkNode(cur);
xmlFreeNode(cur);
return (Z_OK);
@@ -2311,6 +2510,58 @@ zonecfg_modify_nwif(
return (Z_OK);
}
+void
+zonecfg_free_res_attr_list(struct zone_res_attrtab *valtab)
+{
+ if (valtab == NULL)
+ return;
+ zonecfg_free_res_attr_list(valtab->zone_res_attr_next);
+ free(valtab);
+}
+
+int
+zonecfg_add_res_attr(struct zone_res_attrtab **headptr,
+ struct zone_res_attrtab *valtabptr)
+{
+ struct zone_res_attrtab *last, *old, *new;
+
+ last = *headptr;
+ for (old = last; old != NULL; old = old->zone_res_attr_next)
+ last = old; /* walk to the end of the list */
+ new = valtabptr; /* alloc'd by caller */
+ new->zone_res_attr_next = NULL;
+ if (last == NULL)
+ *headptr = new;
+ else
+ last->zone_res_attr_next = new;
+ return (Z_OK);
+}
+
+int
+zonecfg_remove_res_attr(struct zone_res_attrtab **headptr,
+ struct zone_res_attrtab *valtabptr)
+{
+ struct zone_res_attrtab *last, *this, *next;
+
+ last = *headptr;
+ for (this = last; this != NULL; this = this->zone_res_attr_next) {
+ if (strcmp(this->zone_res_attr_name,
+ valtabptr->zone_res_attr_name) == 0 &&
+ strcmp(this->zone_res_attr_value,
+ valtabptr->zone_res_attr_value) == 0) {
+ next = this->zone_res_attr_next;
+ if (this == *headptr)
+ *headptr = next;
+ else
+ last->zone_res_attr_next = next;
+ free(this);
+ return (Z_OK);
+ } else
+ last = this;
+ }
+ return (Z_NO_PROPERTY_ID);
+}
+
/*
* Must be a comma-separated list of alpha-numeric file system names.
*/
@@ -2460,7 +2711,7 @@ zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
int
zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
{
- xmlNodePtr cur, firstmatch;
+ xmlNodePtr cur, val, firstmatch;
int err;
char match[MAXPATHLEN];
@@ -2505,13 +2756,40 @@ zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
sizeof (tabptr->zone_dev_match))) != Z_OK)
return (err);
+ tabptr->zone_dev_attrp = NULL;
+ for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+ struct zone_res_attrtab *valptr;
+
+ valptr = (struct zone_res_attrtab *)malloc(
+ sizeof (struct zone_res_attrtab));
+ if (valptr == NULL)
+ return (Z_NOMEM);
+
+ valptr->zone_res_attr_name[0] =
+ valptr->zone_res_attr_value[0] = '\0';
+ if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
+ != Z_OK) {
+ free(valptr);
+ break;
+ }
+
+ if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+ sizeof (valptr->zone_res_attr_name)) != Z_OK))
+ break;
+ if ((fetchprop(val, DTD_ATTR_VALUE,
+ valptr->zone_res_attr_value,
+ sizeof (valptr->zone_res_attr_value)) != Z_OK))
+ break;
+ }
+
return (Z_OK);
}
static int
zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
{
- xmlNodePtr newnode, cur = handle->zone_dh_cur;
+ xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
+ struct zone_res_attrtab *valptr;
int err;
newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
@@ -2520,6 +2798,21 @@ zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
tabptr->zone_dev_match)) != Z_OK)
return (err);
+ for (valptr = tabptr->zone_dev_attrp; valptr != NULL;
+ valptr = valptr->zone_res_attr_next) {
+ valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
+ NULL);
+ err = newprop(valnode, DTD_ATTR_NAME,
+ valptr->zone_res_attr_name);
+ if (err != Z_OK)
+ return (err);
+ err = newprop(valnode, DTD_ATTR_VALUE,
+ valptr->zone_res_attr_value);
+ if (err != Z_OK)
+ return (err);
+ }
+
+
return (Z_OK);
}
@@ -4734,7 +5027,7 @@ get_pool_sched_class(char *poolname, char *class, int clsize)
pool_conf_t *poolconf;
pool_t *pool;
pool_elem_t *pe;
- pool_value_t *pv = pool_value_alloc();
+ pool_value_t *pv;
const char *sched_str;
if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
@@ -4755,15 +5048,23 @@ get_pool_sched_class(char *poolname, char *class, int clsize)
return (Z_NO_POOL);
}
+ if ((pv = pool_value_alloc()) == NULL) {
+ (void) pool_conf_close(poolconf);
+ pool_conf_free(poolconf);
+ return (Z_NO_POOL);
+ }
+
pe = pool_to_elem(poolconf, pool);
if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
POC_STRING) {
(void) pool_conf_close(poolconf);
+ pool_value_free(pv);
pool_conf_free(poolconf);
return (Z_NO_ENTRY);
}
(void) pool_value_get_string(pv, &sched_str);
(void) pool_conf_close(poolconf);
+ pool_value_free(pv);
pool_conf_free(poolconf);
if (strlcpy(class, sched_str, clsize) >= clsize)
return (Z_TOO_BIG);
@@ -4872,7 +5173,8 @@ zonecfg_setnwifent(zone_dochandle_t handle)
int
zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
{
- xmlNodePtr cur;
+ xmlNodePtr cur, val;
+ struct zone_res_attrtab *valptr;
int err;
if (handle == NULL)
@@ -4908,6 +5210,24 @@ zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
return (err);
}
+ if ((err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
+ sizeof (tabptr->zone_nwif_mac))) != Z_OK) {
+ handle->zone_dh_cur = handle->zone_dh_top;
+ return (err);
+ }
+
+ if ((err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
+ sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK) {
+ handle->zone_dh_cur = handle->zone_dh_top;
+ return (err);
+ }
+
+ if ((err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
+ sizeof (tabptr->zone_nwif_gnic))) != Z_OK) {
+ handle->zone_dh_cur = handle->zone_dh_top;
+ return (err);
+ }
+
if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
tabptr->zone_nwif_defrouter,
sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
@@ -4915,6 +5235,29 @@ zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
return (err);
}
+ tabptr->zone_nwif_attrp = NULL;
+ for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+ valptr = (struct zone_res_attrtab *)malloc(
+ sizeof (struct zone_res_attrtab));
+ if (valptr == NULL)
+ return (Z_NOMEM);
+
+ valptr->zone_res_attr_name[0] =
+ valptr->zone_res_attr_value[0] = '\0';
+ if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
+ != Z_OK) {
+ free(valptr);
+ break;
+ }
+
+ if (fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+ sizeof (valptr->zone_res_attr_name)) != Z_OK)
+ break;
+ if (fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
+ sizeof (valptr->zone_res_attr_value)) != Z_OK)
+ break;
+ }
+
handle->zone_dh_cur = cur->next;
return (Z_OK);
}
@@ -4934,7 +5277,7 @@ zonecfg_setdevent(zone_dochandle_t handle)
int
zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
{
- xmlNodePtr cur;
+ xmlNodePtr cur, val;
int err;
if (handle == NULL)
@@ -4957,6 +5300,31 @@ zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
return (err);
}
+ tabptr->zone_dev_attrp = NULL;
+ for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+ struct zone_res_attrtab *valptr;
+
+ valptr = (struct zone_res_attrtab *)malloc(
+ sizeof (struct zone_res_attrtab));
+ if (valptr == NULL)
+ return (Z_NOMEM);
+
+ valptr->zone_res_attr_name[0] =
+ valptr->zone_res_attr_value[0] = '\0';
+ if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
+ != Z_OK) {
+ free(valptr);
+ break;
+ }
+
+ if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+ sizeof (valptr->zone_res_attr_name)) != Z_OK))
+ break;
+ if ((fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
+ sizeof (valptr->zone_res_attr_value)) != Z_OK))
+ break;
+ }
+
handle->zone_dh_cur = cur->next;
return (Z_OK);
}
@@ -5685,6 +6053,164 @@ zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
}
/*
+ * Atomically get a new zone_did value. The currently allocated value
+ * is stored in /etc/zones/did.txt. Lock the file, read the current value,
+ * increment, save the new value and unlock the file. Return the new value
+ * or -1 if there was an error. The ID namespace is large enough that we
+ * don't worry about recycling an ID when a zone is deleted.
+ */
+static zoneid_t
+new_zone_did()
+{
+ int fd;
+ int len;
+ int val;
+ struct flock lck;
+ char buf[80];
+
+ if ((fd = open(DEBUGID_FILE, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ perror("new_zone_did open failed");
+ return (-1);
+ }
+
+ /* Initialize the lock. */
+ lck.l_whence = SEEK_SET;
+ lck.l_start = 0;
+ lck.l_len = 0;
+
+ /* Wait until we acquire an exclusive lock on the file. */
+ lck.l_type = F_WRLCK;
+ if (fcntl(fd, F_SETLKW, &lck) == -1) {
+ perror("new_zone_did lock failed");
+ (void) close(fd);
+ return (-1);
+ }
+
+ /* Get currently allocated value */
+ len = read(fd, buf, sizeof (buf));
+ if (len == -1) {
+ perror("new_zone_did read failed");
+ val = -1;
+ } else {
+ if (lseek(fd, 0L, SEEK_SET) == -1) {
+ perror("new_zone_did seek failed");
+ val = -1;
+ } else {
+ if (len == 0) {
+ /* Just created the file, initialize at 1 */
+ val = 1;
+ } else {
+ val = atoi(buf);
+ val++;
+ }
+
+ (void) snprintf(buf, sizeof (buf), "%d\n", val);
+ len = strlen(buf);
+
+ /* Save newly allocated value */
+ if (write(fd, buf, len) == -1) {
+ perror("new_zone_did write failed");
+ val = -1;
+ }
+ }
+ }
+
+ /* Release the file lock. */
+ lck.l_type = F_UNLCK;
+ if (fcntl(fd, F_SETLK, &lck) == -1) {
+ perror("new_zone_did unlock failed");
+ val = -1;
+ }
+
+ if (close(fd) != 0)
+ perror("new_zone_did close failed");
+
+ return (val);
+}
+
+/*
+ * Called by zoneadmd to get the zone's debug ID.
+ * If the zone doesn't already have an ID, a new one is generated and
+ * persistently saved onto the zone. Normally either zoneadm or zonecfg
+ * will assign a new ID for the zone, so zoneadmd should never have to
+ * generate one, but we also handle that here just to be paranoid.
+ */
+zoneid_t
+zone_get_did(char *zone_name)
+{
+ int res;
+ zoneid_t new_did;
+ zone_dochandle_t handle;
+ char did_str[80];
+
+ if ((handle = zonecfg_init_handle()) == NULL)
+ return (getpid());
+
+ if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
+ return (getpid());
+
+ res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+
+ /* If the zone already has an assigned debug ID, return it. */
+ if (res == Z_OK && did_str[0] != '\0') {
+ zonecfg_fini_handle(handle);
+ return (atoi(did_str));
+ }
+
+ /*
+ * The zone doesn't have an assigned debug ID yet, generate one and
+ * save it as part of the zone definition.
+ */
+ if ((new_did = new_zone_did()) == -1) {
+ /*
+ * We should really never hit this block of code.
+ * Generating a new ID failed for some reason. Use the current
+ * pid as a temporary ID so that the zone can continue to boot
+ * but we don't persistently save this temporary ID on the zone.
+ */
+ zonecfg_fini_handle(handle);
+ return (getpid());
+ }
+
+ /* Now persistently save this new ID onto the zone. */
+ (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+ (void) setrootattr(handle, DTD_ATTR_DID, did_str);
+ (void) zonecfg_save(handle);
+
+ zonecfg_fini_handle(handle);
+ return (new_did);
+}
+
+zoneid_t
+zonecfg_get_did(zone_dochandle_t handle)
+{
+ char did_str[80];
+ int err;
+ zoneid_t did;
+
+ err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+ if (err == Z_OK && did_str[0] != '\0')
+ did = atoi(did_str);
+ else
+ did = -1;
+
+ return (did);
+}
+
+void
+zonecfg_set_did(zone_dochandle_t handle)
+{
+ zoneid_t new_did;
+ char did_str[80];
+
+ if ((new_did = new_zone_did()) == -1)
+ return;
+ (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+ (void) setrootattr(handle, DTD_ATTR_DID, did_str);
+}
+
+/*
* Return the appropriate root for the active /dev.
* For normal zone, the path is $ZONEPATH/root;
* for scratch zone, the dev path is $ZONEPATH/lu.
@@ -5808,16 +6334,27 @@ int
zone_set_state(char *zone, zone_state_t state)
{
struct zoneent ze;
+ int res;
+ zone_state_t oldst = (zone_state_t)-1;
if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
state != ZONE_STATE_INCOMPLETE)
return (Z_INVAL);
+ (void) zone_get_state(zone, &oldst);
+
bzero(&ze, sizeof (ze));
(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
ze.zone_state = state;
(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
- return (putzoneent(&ze, PZE_MODIFY));
+ res = putzoneent(&ze, PZE_MODIFY);
+
+ if (res == Z_OK) {
+ zonecfg_notify_conf_change(zone, zone_state_str(oldst),
+ zone_state_str(state));
+ }
+
+ return (res);
}
/*
@@ -5967,6 +6504,30 @@ zonecfg_get_uuid(const char *zonename, uuid_t uuid)
}
/*
+ * Changes a zone's UUID to the given value. Returns an error if the UUID is
+ * malformed or if the zone cannot be located.
+ */
+int
+zonecfg_set_uuid(const char *zonename, const char *zonepath,
+ const char *uuid)
+{
+ int err;
+ struct zoneent ze;
+
+ bzero(&ze, sizeof (ze));
+ ze.zone_state = -1; /* Preserve existing state in index */
+ (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
+ (void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path));
+ if (uuid_parse((char *)uuid, ze.zone_uuid) == -1)
+ return (Z_INVALID_PROPERTY);
+
+ if ((err = putzoneent(&ze, PZE_MODIFY)) != Z_OK)
+ return (err);
+
+ return (Z_OK);
+}
+
+/*
* File-system convenience functions.
*/
boolean_t
@@ -6999,86 +7560,49 @@ zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
return (err);
}
-static int
-add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
- xmlNodePtr newnode, cur = handle->zone_dh_cur;
- int err;
-
- newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
- if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
- != Z_OK)
- return (err);
-
- return (Z_OK);
-}
-
+/*
+ * Cleanup obsolete constructs in the configuration.
+ * Return true of the config has been updated and must be commited.
+ */
int
-zonecfg_delete_mcap(zone_dochandle_t handle)
+zonecfg_fix_obsolete(zone_dochandle_t handle)
{
- int err;
- xmlNodePtr cur = handle->zone_dh_cur;
+ int res = 0;
+ int add_physmem_rctl = 0;
+ xmlNodePtr cur;
+ char zone_physmem_cap[MAXNAMELEN];
- if ((err = operation_prep(handle)) != Z_OK)
- return (err);
+ if (operation_prep(handle) != Z_OK)
+ return (res);
+ /*
+ * If an obsolete mcap entry exists, convert it to the rctl.
+ */
+ cur = handle->zone_dh_cur;
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
continue;
+ if (fetchprop(cur, DTD_ATTR_PHYSCAP,
+ zone_physmem_cap, sizeof (zone_physmem_cap)) == Z_OK) {
+ res = 1;
+ add_physmem_rctl = 1;
+ }
+
xmlUnlinkNode(cur);
xmlFreeNode(cur);
- return (Z_OK);
+ break;
}
- return (Z_NO_RESOURCE_ID);
-}
-int
-zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
- int err;
+ if (add_physmem_rctl) {
+ uint64_t cap;
+ char *endp;
- if (tabptr == NULL)
- return (Z_INVAL);
-
- err = zonecfg_delete_mcap(handle);
- /* it is ok if there is no mcap entry */
- if (err != Z_OK && err != Z_NO_RESOURCE_ID)
- return (err);
-
- if ((err = add_mcap(handle, tabptr)) != Z_OK)
- return (err);
-
- return (Z_OK);
-}
-
-int
-zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
- xmlNodePtr cur;
- int err;
-
- if (tabptr == NULL)
- return (Z_INVAL);
-
- if ((err = operation_prep(handle)) != Z_OK)
- return (err);
-
- cur = handle->zone_dh_cur;
- for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
- if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
- continue;
- if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
- tabptr->zone_physmem_cap,
- sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (err);
- }
-
- return (Z_OK);
+ cap = strtoull(zone_physmem_cap, &endp, 10);
+ (void) zonecfg_set_aliased_rctl(handle, ALIAS_MAXPHYSMEM, cap);
}
- return (Z_NO_ENTRY);
+ return (res);
}
int
@@ -7136,51 +7660,6 @@ zonecfg_getsecflagsent(zone_dochandle_t handle,
return (err);
}
-static int
-getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
- xmlNodePtr cur;
- int err;
-
- if (handle == NULL)
- return (Z_INVAL);
-
- if ((cur = handle->zone_dh_cur) == NULL)
- return (Z_NO_ENTRY);
-
- for (; cur != NULL; cur = cur->next)
- if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
- break;
- if (cur == NULL) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (Z_NO_ENTRY);
- }
-
- if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
- sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
- handle->zone_dh_cur = handle->zone_dh_top;
- return (err);
- }
-
- handle->zone_dh_cur = cur->next;
- return (Z_OK);
-}
-
-int
-zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
- int err;
-
- if ((err = zonecfg_setent(handle)) != Z_OK)
- return (err);
-
- err = getmcapent_core(handle, tabptr);
-
- (void) zonecfg_endent(handle);
-
- return (err);
-}
-
/*
* Get the full tree of pkg metadata in a set of nested AVL trees.
* pkgs_avl is an AVL tree of pkgs.
@@ -7846,7 +8325,7 @@ zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
(void) fclose(uaf);
return (Z_MISC_FS);
}
- if (!config_file_path(zonename, config_file)) {
+ if (!config_file_path(zonename, config_file, sizeof (config_file))) {
(void) fclose(uaf);
return (Z_MISC_FS);
}
diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers
index c73533b97f..da4009d2fa 100644
--- a/usr/src/lib/libzonecfg/common/mapfile-vers
+++ b/usr/src/lib/libzonecfg/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015, Joyent Inc.
#
#
@@ -53,6 +54,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_add_fs_option;
zonecfg_add_admin;
zonecfg_add_nwif;
+ zonecfg_add_res_attr;
zonecfg_add_pkg;
zonecfg_add_pset;
zonecfg_add_rctl;
@@ -80,7 +82,6 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_delete_dev;
zonecfg_delete_ds;
zonecfg_delete_filesystem;
- zonecfg_delete_mcap;
zonecfg_delete_nwif;
zonecfg_delete_pset;
zonecfg_delete_rctl;
@@ -106,7 +107,9 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_find_mounts;
zonecfg_find_scratch;
zonecfg_fini_handle;
+ zonecfg_fix_obsolete;
zonecfg_free_fs_option_list;
+ zonecfg_free_res_attr_list;
zonecfg_free_rctl_value_list;
zonecfg_get_aliased_rctl;
zonecfg_get_attach_handle;
@@ -120,6 +123,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_get_bootargs;
zonecfg_get_brand;
zonecfg_get_dflt_sched_class;
+ zonecfg_get_did;
zonecfg_getdevent;
zonecfg_getdevperment;
zonecfg_getdsent;
@@ -129,7 +133,6 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_get_hostid;
zonecfg_get_iptype;
zonecfg_get_limitpriv;
- zonecfg_getmcapent;
zonecfg_get_name;
zonecfg_get_name_by_uuid;
zonecfg_getnwifent;
@@ -163,7 +166,6 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_lookup_dev;
zonecfg_lookup_ds;
zonecfg_lookup_filesystem;
- zonecfg_lookup_mcap;
zonecfg_lookup_nwif;
zonecfg_lookup_pset;
zonecfg_lookup_rctl;
@@ -173,12 +175,12 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_modify_dev;
zonecfg_modify_ds;
zonecfg_modify_filesystem;
- zonecfg_modify_mcap;
zonecfg_modify_nwif;
zonecfg_modify_pset;
zonecfg_modify_rctl;
zonecfg_modify_secflags;
zonecfg_notify_bind;
+ zonecfg_notify_create;
zonecfg_notify_critical_abort;
zonecfg_notify_critical_enter;
zonecfg_notify_critical_exit;
@@ -188,6 +190,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_ping_zoneadmd;
zonecfg_release_lock_file;
zonecfg_remove_fs_option;
+ zonecfg_remove_res_attr;
zonecfg_remove_rctl_value;
zonecfg_remove_userauths;
zonecfg_reverse_scratch;
@@ -201,6 +204,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_set_autoboot;
zonecfg_set_bootargs;
zonecfg_set_brand;
+ zonecfg_set_did;
zonecfg_setdevent;
zonecfg_setdevperment;
zonecfg_setdsent;
@@ -216,6 +220,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_set_root;
zonecfg_set_sched;
zonecfg_set_swinv;
+ zonecfg_set_uuid;
zonecfg_set_zonepath;
zonecfg_strerror;
zonecfg_str_to_bytes;
@@ -234,6 +239,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zonecfg_verify_save;
zonecfg_warn_poold;
zone_get_brand;
+ zone_get_did;
zone_get_devroot;
zone_get_id;
zone_get_rootpath;
diff --git a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
index 03be1a2bf5..228bb8ace2 100644
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
@@ -21,6 +21,7 @@
CDDL HEADER END
Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2011, Joyent Inc. All rights reserved.
-->
@@ -46,14 +47,21 @@
<!ATTLIST inherited-pkg-dir directory CDATA #REQUIRED>
-<!ELEMENT network EMPTY>
+<!ELEMENT net-attr EMPTY>
+<!ATTLIST net-attr name CDATA #REQUIRED
+ value CDATA #REQUIRED>
+
+<!ELEMENT network (net-attr)*>
<!ATTLIST network address CDATA ""
allowed-address CDATA ""
defrouter CDATA ""
- physical CDATA #REQUIRED>
+ global-nic CDATA ""
+ mac-addr CDATA ""
+ physical CDATA #REQUIRED
+ vlan-id CDATA "">
-<!ELEMENT device EMPTY>
+<!ELEMENT device (net-attr)*>
<!ATTLIST device match CDATA #REQUIRED>
@@ -162,6 +170,7 @@
limitpriv CDATA ""
bootargs CDATA ""
brand CDATA ""
+ debugid CDATA ""
scheduling-class CDATA ""
fs-allowed CDATA ""
version NMTOKEN #FIXED '1'>
diff --git a/usr/src/lib/libzpool/common/sys/zfs_context.h b/usr/src/lib/libzpool/common/sys/zfs_context.h
index b858ea719b..bc43d455e0 100644
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h
@@ -21,8 +21,8 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#ifndef _SYS_ZFS_CONTEXT_H
diff --git a/usr/src/lib/mergeq/mergeq.c b/usr/src/lib/mergeq/mergeq.c
new file mode 100644
index 0000000000..fd9a9c32ea
--- /dev/null
+++ b/usr/src/lib/mergeq/mergeq.c
@@ -0,0 +1,606 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Merge queue
+ *
+ * A multi-threaded merging queue.
+ *
+ * The general constraint of the merge queue is that if a set of items are
+ * inserted into the queue in the same order, then no matter how many threads
+ * are on the scene, we will always process the items in the same order. The
+ * secondary constraint is that to support environments that must be
+ * single-threaded, we explicitly *must not* create a thread in the case where
+ * the number of requested threads is just one.
+ *
+ * To that end, we've designed our queue as a circular buffer. We will grow that
+ * buffer to contain enough space for all the input items, after which we'll
+ * then treat it as a circular buffer.
+ *
+ * Items will be issued to a processing function two at a time, until there is
+ * only one item remaining in the queue, at which point we will be doing doing
+ * any merging work.
+ *
+ * A given queue has three different entries that we care about tracking:
+ *
+ * o mq_nproc - What is the slot of the next item to process for something
+ * looking for work.
+ *
+ * o mq_next - What is the slot of the next item that should be inserted into
+ * the queue.
+ *
+ * o mq_ncommit - What is the slot of the next item that should be committed.
+ *
+ * When a thread comes and looks for work, we pop entries off of the queue based
+ * on the index provided by mq_nproc. At the same time, it also gets the slot
+ * that it should place the result in, which is mq_next. However, because we
+ * have multiple threads that are operating on the system, we want to make sure
+ * that we push things onto the queue in order. We do that by allocating a slot
+ * to each task and when it completes, it waits for its slot to be ready based
+ * on it being the value of mq_ncommit.
+ *
+ * In addition, we keep track of the number of items in the queue as well as the
+ * number of active workers. There's also a generation count that is used to
+ * figure out when the various values might lap one another.
+ *
+ * The following images show what happens when we have a queue with six items
+ * and whose capacity has been shrunk to six, to better fit in the screen.
+ *
+ *
+ * 1) This is the initial configuration of the queue right before any processing
+ * is done in the context of mergeq_merge(). Every box has an initial item for
+ * merging in it (represented by an 'x'). Here, the mq_nproc, mq_next, and
+ * mq_ncommit will all point at the initial entry. However, the mq_next has
+ * already lapped around the array and thus has a generation count of one.
+ *
+ * The '+' characters indicate which bucket the corresponding value of mq_nproc,
+ * mq_ncommit, and mq_nproc.
+ *
+ * +---++---++---++---++---++---+
+ * | X || X || X || X || X || X |
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 2) This shows the state right as the first thread begins to process an entry.
+ * Note in this example we will have two threads processing this queue. Note,
+ * mq_ncommit has not advanced. This is because the first thread has started
+ * processing entries, but it has not finished, and thus we can't commit it.
+ * We've incremented mq_next by one because it has gone ahead and assigned a
+ * single entry. We've incremented mq_nproc by two, because we have removed two
+ * entries and thus will have another set available.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 0
+ * | || || X || X || X || X | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ *
+ * 3) This shows the state right after the second thread begins to process an
+ * entry, note that the first thread has not finished. The changes are very
+ * similar to the previous state, we've advanced, mq_nproc and mq_next, but not
+ * mq_ncommit.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 0
+ * | || || || || X || X | t2 - slot 1
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 4) This shows the state after thread one has finished processing an item, but
+ * before it does anything else. Note that even if thread two finishes early, it
+ * cannot commit its item until thread one finishes. Here 'Y' refers to the
+ * result of merging the first two 'X's.
+ *
+ * +---++---++---++---++---++---+ t1 - idle
+ * | Y || || || || X || X | t2 - slot 1
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 5) This shows the state after thread one has begun to process the next round
+ * and after thread two has committed, but before it begins processing the next
+ * item. Note that mq_nproc has wrapped around and we've bumped its generation
+ * counter.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 2
+ * | Y || Y || || || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 6) Here, thread two, will take the next two Y values and thread 1 will commit
+ * its 'Y'. Thread one now must wait until thread two finishes such that it can
+ * do additional work.
+ *
+ * +---++---++---++---++---++---+ t1 - waiting
+ * | || || Y || || || | t2 - slot 3
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 7) Here, thread two has committed and thread one is about to go process the
+ * final entry. The character 'Z' represents the results of merging two 'Y's.
+ *
+ * +---++---++---++---++---++---+ t1 - idle
+ * | || || Y || Z || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 8) Here, thread one is processing the final item. Thread two is waiting in
+ * mergeq_pop() for enough items to be available. In this case, it will never
+ * happen; however, once all threads have finished it will break out.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 4
+ * | || || || || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 9) This is the final state of the queue, it has a single '*' item which is
+ * the final merge result. At this point, both thread one and thread two would
+ * stop processing and we'll return the result to the user.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 4
+ * | || || || || * || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ *
+ * Note, that if at any point in time the processing function fails, then all
+ * the merges will quiesce and that error will be propagated back to the user.
+ */
+
+#include <strings.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "mergeq.h"
+
+struct mergeq {
+ mutex_t mq_lock; /* Protects items below */
+ cond_t mq_cond; /* Condition variable */
+ void **mq_items; /* Array of items to process */
+ size_t mq_nitems; /* Number of items in the queue */
+ size_t mq_cap; /* Capacity of the items */
+ size_t mq_next; /* Place to put next entry */
+ size_t mq_gnext; /* Generation for next */
+ size_t mq_nproc; /* Index of next thing to process */
+ size_t mq_gnproc; /* Generation for next proc */
+ size_t mq_ncommit; /* Index of the next thing to commit */
+ size_t mq_gncommit; /* Commit generation */
+ uint_t mq_nactthrs; /* Number of active threads */
+ uint_t mq_ndthreads; /* Desired number of threads */
+ thread_t *mq_thrs; /* Actual threads */
+ mergeq_proc_f *mq_func; /* Processing function */
+ void *mq_arg; /* Argument for processing */
+ boolean_t mq_working; /* Are we working on processing */
+ boolean_t mq_iserror; /* Have we encountered an error? */
+ int mq_error;
+};
+
+#define MERGEQ_DEFAULT_CAP 64
+
+static int
+mergeq_error(int err)
+{
+ errno = err;
+ return (MERGEQ_ERROR);
+}
+
+void
+mergeq_fini(mergeq_t *mqp)
+{
+ if (mqp == NULL)
+ return;
+
+ VERIFY(mqp->mq_working != B_TRUE);
+
+ if (mqp->mq_items != NULL)
+ mergeq_free(mqp->mq_items, sizeof (void *) * mqp->mq_cap);
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs, sizeof (thread_t) *
+ mqp->mq_ndthreads);
+ }
+ VERIFY0(cond_destroy(&mqp->mq_cond));
+ VERIFY0(mutex_destroy(&mqp->mq_lock));
+ mergeq_free(mqp, sizeof (mergeq_t));
+}
+
+int
+mergeq_init(mergeq_t **outp, uint_t nthrs)
+{
+ int ret;
+ mergeq_t *mqp;
+
+ mqp = mergeq_alloc(sizeof (mergeq_t));
+ if (mqp == NULL)
+ return (mergeq_error(ENOMEM));
+
+ bzero(mqp, sizeof (mergeq_t));
+ mqp->mq_items = mergeq_alloc(sizeof (void *) * MERGEQ_DEFAULT_CAP);
+ if (mqp->mq_items == NULL) {
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ENOMEM));
+ }
+ bzero(mqp->mq_items, sizeof (void *) * MERGEQ_DEFAULT_CAP);
+
+ mqp->mq_ndthreads = nthrs - 1;
+ if (mqp->mq_ndthreads > 0) {
+ mqp->mq_thrs = mergeq_alloc(sizeof (thread_t) *
+ mqp->mq_ndthreads);
+ if (mqp->mq_thrs == NULL) {
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ENOMEM));
+ }
+ }
+
+ if ((ret = mutex_init(&mqp->mq_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs,
+ sizeof (thread_t) * mqp->mq_ndthreads);
+ }
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ret));
+ }
+
+ if ((ret = cond_init(&mqp->mq_cond, USYNC_THREAD, NULL)) != 0) {
+ VERIFY0(mutex_destroy(&mqp->mq_lock));
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs,
+ sizeof (thread_t) * mqp->mq_ndthreads);
+ }
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ret));
+ }
+
+ mqp->mq_cap = MERGEQ_DEFAULT_CAP;
+ *outp = mqp;
+ return (0);
+}
+
+static void
+mergeq_reset(mergeq_t *mqp)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_working == B_FALSE);
+ if (mqp->mq_cap != 0)
+ bzero(mqp->mq_items, sizeof (void *) * mqp->mq_cap);
+ mqp->mq_nitems = 0;
+ mqp->mq_next = 0;
+ mqp->mq_gnext = 0;
+ mqp->mq_nproc = 0;
+ mqp->mq_gnproc = 0;
+ mqp->mq_ncommit = 0;
+ mqp->mq_gncommit = 0;
+ mqp->mq_func = NULL;
+ mqp->mq_arg = NULL;
+ mqp->mq_iserror = B_FALSE;
+ mqp->mq_error = 0;
+}
+
+static int
+mergeq_grow(mergeq_t *mqp)
+{
+ size_t ncap;
+ void **items;
+
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_working == B_FALSE);
+
+ if (SIZE_MAX - mqp->mq_cap < MERGEQ_DEFAULT_CAP)
+ return (ENOSPC);
+
+ ncap = mqp->mq_cap + MERGEQ_DEFAULT_CAP;
+ items = mergeq_alloc(ncap * sizeof (void *));
+ if (items == NULL)
+ return (ENOMEM);
+
+ bzero(items, ncap * sizeof (void *));
+ bcopy(mqp->mq_items, items, mqp->mq_cap * sizeof (void *));
+ mergeq_free(mqp->mq_items, sizeof (mqp->mq_cap) * sizeof (void *));
+ mqp->mq_items = items;
+ mqp->mq_cap = ncap;
+ return (0);
+}
+
+int
+mergeq_add(mergeq_t *mqp, void *item)
+{
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+ if (mqp->mq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(ENXIO));
+ }
+
+ if (mqp->mq_next == mqp->mq_cap) {
+ int ret;
+
+ if ((ret = mergeq_grow(mqp)) != 0) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(ret));
+ }
+ }
+ mqp->mq_items[mqp->mq_next] = item;
+ mqp->mq_next++;
+ mqp->mq_nitems++;
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (0);
+}
+
+static size_t
+mergeq_slot(mergeq_t *mqp)
+{
+ size_t s;
+
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_next < mqp->mq_cap);
+
+ /*
+ * This probably should be a cv / wait thing.
+ */
+ VERIFY(mqp->mq_nproc != (mqp->mq_next + 1) % mqp->mq_cap);
+
+ s = mqp->mq_next;
+ mqp->mq_next++;
+ if (mqp->mq_next == mqp->mq_cap) {
+ mqp->mq_next %= mqp->mq_cap;
+ mqp->mq_gnext++;
+ }
+
+ return (s);
+}
+
+/*
+ * Internal function to push items onto the queue which is now a circular
+ * buffer. This should only be used once we begin working on the queue.
+ */
+static void
+mergeq_push(mergeq_t *mqp, size_t slot, void *item)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(slot < mqp->mq_cap);
+
+ /*
+ * We need to verify that we don't push over something that exists.
+ * Based on the design, this should never happen. However, in the face
+ * of bugs, anything is possible.
+ */
+ while (mqp->mq_ncommit != slot && mqp->mq_iserror == B_FALSE)
+ (void) cond_wait(&mqp->mq_cond, &mqp->mq_lock);
+
+ if (mqp->mq_iserror == B_TRUE)
+ return;
+
+ mqp->mq_items[slot] = item;
+ mqp->mq_nitems++;
+ mqp->mq_ncommit++;
+ if (mqp->mq_ncommit == mqp->mq_cap) {
+ mqp->mq_ncommit %= mqp->mq_cap;
+ mqp->mq_gncommit++;
+ }
+ cond_broadcast(&mqp->mq_cond);
+}
+
+static void *
+mergeq_pop_one(mergeq_t *mqp)
+{
+ void *out;
+
+ /*
+ * We can't move mq_nproc beyond mq_next if they're on the same
+ * generation.
+ */
+ VERIFY(mqp->mq_gnext != mqp->mq_gnproc ||
+ mqp->mq_nproc != mqp->mq_next);
+
+ out = mqp->mq_items[mqp->mq_nproc];
+
+ mqp->mq_items[mqp->mq_nproc] = NULL;
+ mqp->mq_nproc++;
+ if (mqp->mq_nproc == mqp->mq_cap) {
+ mqp->mq_nproc %= mqp->mq_cap;
+ mqp->mq_gnproc++;
+ }
+ mqp->mq_nitems--;
+
+ return (out);
+}
+
+/*
+ * Pop a set of two entries from the queue. We may not have anything to process
+ * at the moment, eg. be waiting for someone to add something. In which case,
+ * we'll be sitting and waiting.
+ */
+static boolean_t
+mergeq_pop(mergeq_t *mqp, void **first, void **second)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_nproc < mqp->mq_cap);
+
+ while (mqp->mq_nitems < 2 && mqp->mq_nactthrs > 0 &&
+ mqp->mq_iserror == B_FALSE)
+ (void) cond_wait(&mqp->mq_cond, &mqp->mq_lock);
+
+ if (mqp->mq_iserror == B_TRUE)
+ return (B_FALSE);
+
+ if (mqp->mq_nitems < 2 && mqp->mq_nactthrs == 0) {
+ VERIFY(mqp->mq_iserror == B_TRUE || mqp->mq_nitems == 1);
+ return (B_FALSE);
+ }
+ VERIFY(mqp->mq_nitems >= 2);
+
+ *first = mergeq_pop_one(mqp);
+ *second = mergeq_pop_one(mqp);
+
+ return (B_TRUE);
+}
+
+static void *
+mergeq_thr_merge(void *arg)
+{
+ mergeq_t *mqp = arg;
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ /*
+ * Check to make sure creation worked and if not, fail fast.
+ */
+ if (mqp->mq_iserror == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+
+ for (;;) {
+ void *first, *second, *out;
+ int ret;
+ size_t slot;
+
+ if (mqp->mq_nitems == 1 && mqp->mq_nactthrs == 0) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+
+ if (mergeq_pop(mqp, &first, &second) == B_FALSE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+ slot = mergeq_slot(mqp);
+
+ mqp->mq_nactthrs++;
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ ret = mqp->mq_func(first, second, &out, mqp->mq_arg);
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ if (ret != 0) {
+ if (mqp->mq_iserror == B_FALSE) {
+ mqp->mq_iserror = B_TRUE;
+ mqp->mq_error = ret;
+ cond_broadcast(&mqp->mq_cond);
+ }
+ mqp->mq_nactthrs--;
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+ mergeq_push(mqp, slot, out);
+ mqp->mq_nactthrs--;
+ }
+}
+
+int
+mergeq_merge(mergeq_t *mqp, mergeq_proc_f *func, void *arg, void **outp,
+ int *errp)
+{
+ int ret, i;
+ boolean_t seterr = B_FALSE;
+
+ if (mqp == NULL || func == NULL || outp == NULL) {
+ return (mergeq_error(EINVAL));
+ }
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+ if (mqp->mq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(EBUSY));
+ }
+
+ if (mqp->mq_nitems == 0) {
+ *outp = NULL;
+ mergeq_reset(mqp);
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (0);
+ }
+
+ /*
+ * Now that we've finished adding items to the queue, turn it into a
+ * circular buffer.
+ */
+ mqp->mq_func = func;
+ mqp->mq_arg = arg;
+ mqp->mq_nproc = 0;
+ mqp->mq_working = B_TRUE;
+ if (mqp->mq_next == mqp->mq_cap) {
+ mqp->mq_next %= mqp->mq_cap;
+ mqp->mq_gnext++;
+ }
+ mqp->mq_ncommit = mqp->mq_next;
+
+ ret = 0;
+ for (i = 0; i < mqp->mq_ndthreads; i++) {
+ ret = thr_create(NULL, 0, mergeq_thr_merge, mqp, 0,
+ &mqp->mq_thrs[i]);
+ if (ret != 0) {
+ mqp->mq_iserror = B_TRUE;
+ break;
+ }
+ }
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ if (ret == 0)
+ (void) mergeq_thr_merge(mqp);
+
+ for (i = 0; i < mqp->mq_ndthreads; i++) {
+ VERIFY0(thr_join(mqp->mq_thrs[i], NULL, NULL));
+ }
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ VERIFY(mqp->mq_nactthrs == 0);
+ mqp->mq_working = B_FALSE;
+ if (ret == 0 && mqp->mq_iserror == B_FALSE) {
+ VERIFY(mqp->mq_nitems == 1);
+ *outp = mergeq_pop_one(mqp);
+ } else if (ret == 0 && mqp->mq_iserror == B_TRUE) {
+ ret = MERGEQ_UERROR;
+ if (errp != NULL)
+ *errp = mqp->mq_error;
+ } else {
+ seterr = B_TRUE;
+ }
+
+ mergeq_reset(mqp);
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+
+ if (seterr == B_TRUE)
+ return (mergeq_error(ret));
+
+ return (ret);
+}
diff --git a/usr/src/lib/mergeq/mergeq.h b/usr/src/lib/mergeq/mergeq.h
new file mode 100644
index 0000000000..4c1a21d696
--- /dev/null
+++ b/usr/src/lib/mergeq/mergeq.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _MERGEQ_H
+#define _MERGEQ_H
+
+/*
+ * mergeq library routines
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mergeq mergeq_t;
+typedef int (mergeq_proc_f)(void *, void *, void **, void *);
+
+extern int mergeq_init(mergeq_t **, uint_t);
+extern void mergeq_fini(mergeq_t *);
+
+extern int mergeq_add(mergeq_t *, void *);
+
+#define MERGEQ_ERROR -1
+#define MERGEQ_UERROR -2
+extern int mergeq_merge(mergeq_t *, mergeq_proc_f *, void *, void **, int *);
+
+/*
+ * Routines consumers need to implement
+ */
+extern void *mergeq_alloc(size_t);
+extern void mergeq_free(void *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MERGEQ_H */
diff --git a/usr/src/lib/mergeq/workq.c b/usr/src/lib/mergeq/workq.c
new file mode 100644
index 0000000000..b9f1f2aa1c
--- /dev/null
+++ b/usr/src/lib/mergeq/workq.c
@@ -0,0 +1,311 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Work queue
+ *
+ * A multi-threaded work queue.
+ *
+ * The general design of this is to add a fixed number of items to the queue and
+ * then drain them with the specified number of threads.
+ */
+
+#include <strings.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "workq.h"
+
+struct workq {
+ mutex_t wq_lock; /* Protects below items */
+ cond_t wq_cond; /* Condition variable */
+ void **wq_items; /* Array of items to process */
+ size_t wq_nitems; /* Number of items in queue */
+ size_t wq_cap; /* Queue capacity */
+ size_t wq_next; /* Next item to process */
+ uint_t wq_ndthreads; /* Desired number of threads */
+ thread_t *wq_thrs; /* Actual threads */
+ workq_proc_f *wq_func; /* Processing function */
+ void *wq_arg; /* Argument for processing */
+ boolean_t wq_working; /* Are we actively using it? */
+ boolean_t wq_iserror; /* Have we encountered an error? */
+ int wq_error; /* Error value, if any */
+};
+
+#define WORKQ_DEFAULT_CAP 64
+
+static int
+workq_error(int err)
+{
+ VERIFY(err != 0);
+ errno = err;
+ return (WORKQ_ERROR);
+}
+
+void
+workq_fini(workq_t *wqp)
+{
+ if (wqp == NULL)
+ return;
+
+ VERIFY(wqp->wq_working != B_TRUE);
+ VERIFY0(mutex_destroy(&wqp->wq_lock));
+ VERIFY0(cond_destroy(&wqp->wq_cond));
+ if (wqp->wq_cap > 0)
+ workq_free(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ if (wqp->wq_ndthreads > 0)
+ workq_free(wqp->wq_thrs, sizeof (thread_t) * wqp->wq_ndthreads);
+ workq_free(wqp, sizeof (workq_t));
+}
+
+int
+workq_init(workq_t **outp, uint_t nthrs)
+{
+ int ret;
+ workq_t *wqp;
+
+ wqp = workq_alloc(sizeof (workq_t));
+ if (wqp == NULL)
+ return (workq_error(ENOMEM));
+
+ bzero(wqp, sizeof (workq_t));
+ wqp->wq_items = workq_alloc(sizeof (void *) * WORKQ_DEFAULT_CAP);
+ if (wqp->wq_items == NULL) {
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ENOMEM));
+ }
+ bzero(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+
+ wqp->wq_ndthreads = nthrs - 1;
+ if (wqp->wq_ndthreads > 0) {
+ wqp->wq_thrs = workq_alloc(sizeof (thread_t) *
+ wqp->wq_ndthreads);
+ if (wqp->wq_thrs == NULL) {
+ workq_free(wqp->wq_items, sizeof (void *) *
+ WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ENOMEM));
+ }
+ }
+
+ if ((ret = mutex_init(&wqp->wq_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ if (wqp->wq_ndthreads > 0) {
+ workq_free(wqp->wq_thrs,
+ sizeof (thread_t) * wqp->wq_ndthreads);
+ }
+ workq_free(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ret));
+ }
+
+ if ((ret = cond_init(&wqp->wq_cond, USYNC_THREAD, NULL)) != 0) {
+ VERIFY0(mutex_destroy(&wqp->wq_lock));
+ if (wqp->wq_ndthreads > 0) {
+ workq_free(wqp->wq_thrs,
+ sizeof (thread_t) * wqp->wq_ndthreads);
+ }
+ workq_free(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ret));
+ }
+
+ wqp->wq_cap = WORKQ_DEFAULT_CAP;
+ *outp = wqp;
+ return (0);
+}
+
+static void
+workq_reset(workq_t *wqp)
+{
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_FALSE);
+ if (wqp->wq_cap > 0)
+ bzero(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ wqp->wq_nitems = 0;
+ wqp->wq_next = 0;
+ wqp->wq_func = NULL;
+ wqp->wq_arg = NULL;
+ wqp->wq_iserror = B_FALSE;
+ wqp->wq_error = 0;
+}
+
+static int
+workq_grow(workq_t *wqp)
+{
+ size_t ncap;
+ void **items;
+
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_FALSE);
+
+ if (SIZE_MAX - wqp->wq_cap < WORKQ_DEFAULT_CAP)
+ return (ENOSPC);
+
+ ncap = wqp->wq_cap + WORKQ_DEFAULT_CAP;
+ items = workq_alloc(ncap * sizeof (void *));
+ if (items == NULL)
+ return (ENOMEM);
+
+ bzero(items, ncap * sizeof (void *));
+ bcopy(wqp->wq_items, items, wqp->wq_cap * sizeof (void *));
+ workq_free(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ wqp->wq_items = items;
+ wqp->wq_cap = ncap;
+ return (0);
+}
+
+int
+workq_add(workq_t *wqp, void *item)
+{
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ if (wqp->wq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(ENXIO));
+ }
+
+ if (wqp->wq_nitems == wqp->wq_cap) {
+ int ret;
+
+ if ((ret = workq_grow(wqp)) != 0) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(ret));
+ }
+ }
+
+ wqp->wq_items[wqp->wq_nitems] = item;
+ wqp->wq_nitems++;
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+
+ return (0);
+}
+
+static void *
+workq_pop(workq_t *wqp)
+{
+ void *out;
+
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_next < wqp->wq_nitems);
+
+ out = wqp->wq_items[wqp->wq_next];
+ wqp->wq_items[wqp->wq_next] = NULL;
+ wqp->wq_next++;
+
+ return (out);
+}
+
+static void *
+workq_thr_work(void *arg)
+{
+ workq_t *wqp = arg;
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_TRUE);
+
+ for (;;) {
+ int ret;
+ void *item;
+
+ if (wqp->wq_iserror == B_TRUE ||
+ wqp->wq_next == wqp->wq_nitems) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (NULL);
+ }
+
+ item = workq_pop(wqp);
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ ret = wqp->wq_func(item, wqp->wq_arg);
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+
+ if (ret != 0) {
+ if (wqp->wq_iserror == B_FALSE) {
+ wqp->wq_iserror = B_TRUE;
+ wqp->wq_error = ret;
+ }
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (NULL);
+ }
+ }
+}
+
+int
+workq_work(workq_t *wqp, workq_proc_f *func, void *arg, int *errp)
+{
+ int i, ret;
+ boolean_t seterr = B_FALSE;
+
+ if (wqp == NULL || func == NULL)
+ return (workq_error(EINVAL));
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ if (wqp->wq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(EBUSY));
+ }
+
+ if (wqp->wq_nitems == 0) {
+ workq_reset(wqp);
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (0);
+ }
+
+ wqp->wq_func = func;
+ wqp->wq_arg = arg;
+ wqp->wq_next = 0;
+ wqp->wq_working = B_TRUE;
+
+ ret = 0;
+ for (i = 0; i < wqp->wq_ndthreads; i++) {
+ ret = thr_create(NULL, 0, workq_thr_work, wqp, 0,
+ &wqp->wq_thrs[i]);
+ if (ret != 0) {
+ wqp->wq_iserror = B_TRUE;
+ }
+ }
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ if (ret == 0)
+ (void) workq_thr_work(wqp);
+
+ for (i = 0; i < wqp->wq_ndthreads; i++) {
+ VERIFY0(thr_join(wqp->wq_thrs[i], NULL, NULL));
+ }
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ wqp->wq_working = B_FALSE;
+ if (ret == 0 && wqp->wq_iserror == B_TRUE) {
+ ret = WORKQ_UERROR;
+ if (errp != NULL)
+ *errp = wqp->wq_error;
+ } else if (ret != 0) {
+ VERIFY(wqp->wq_iserror == B_FALSE);
+ seterr = B_TRUE;
+ }
+
+ workq_reset(wqp);
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+
+ if (seterr == B_TRUE)
+ return (workq_error(ret));
+
+ return (ret);
+}
diff --git a/usr/src/lib/mergeq/workq.h b/usr/src/lib/mergeq/workq.h
new file mode 100644
index 0000000000..20cfec4a95
--- /dev/null
+++ b/usr/src/lib/mergeq/workq.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _WORKQ_H
+#define _WORKQ_H
+
+/*
+ * workq library routines
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct workq workq_t;
+typedef int (workq_proc_f)(void *, void *);
+
+extern int workq_init(workq_t **, uint_t);
+extern void workq_fini(workq_t *);
+
+extern int workq_add(workq_t *, void *);
+
+#define WORKQ_ERROR (-1)
+#define WORKQ_UERROR (-2)
+extern int workq_work(workq_t *, workq_proc_f *, void *, int *);
+
+/*
+ * Routines consumers need to implement
+ */
+extern void *workq_alloc(size_t);
+extern void workq_free(void *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WORKQ_H */
diff --git a/usr/src/lib/nsswitch/dns/Makefile.com b/usr/src/lib/nsswitch/dns/Makefile.com
index 60716d843d..0366633c0c 100644
--- a/usr/src/lib/nsswitch/dns/Makefile.com
+++ b/usr/src/lib/nsswitch/dns/Makefile.com
@@ -44,5 +44,5 @@ CPPFLAGS += -DNSS_DNS_LIBRESOLV=\"libresolv.so.2\"
LINTFLAGS += -erroff=E_GLOBAL_COULD_BE_STATIC2
-LDLIBS += -lnsl -lsocket
+LDLIBS += -lnsl -lresolv_joy -lsocket
DYNLIB1 = nss_dns.so$(VERS)
diff --git a/usr/src/lib/nsswitch/dns/common/dns_common.h b/usr/src/lib/nsswitch/dns/common/dns_common.h
index 717f56d70f..83d486cf57 100644
--- a/usr/src/lib/nsswitch/dns/common/dns_common.h
+++ b/usr/src/lib/nsswitch/dns/common/dns_common.h
@@ -31,8 +31,6 @@
#ifndef _DNS_COMMON_H
#define _DNS_COMMON_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
@@ -43,7 +41,7 @@
#include <thread.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
-#include <resolv.h>
+#include <resolv_joy.h>
#include <syslog.h>
#include <nsswitch.h>
#include <nss_common.h>
diff --git a/usr/src/lib/nsswitch/dns/common/dns_mt.c b/usr/src/lib/nsswitch/dns/common/dns_mt.c
index 128b1bde75..4af3f671c0 100644
--- a/usr/src/lib/nsswitch/dns/common/dns_mt.c
+++ b/usr/src/lib/nsswitch/dns/common/dns_mt.c
@@ -23,8 +23,9 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
/*
* dns_mt.c
@@ -49,52 +50,41 @@
static void _nss_dns_init(void);
extern struct hostent *res_gethostbyname(const char *);
-#pragma weak res_gethostbyname
-#define RES_SET_NO_HOSTS_FALLBACK "__res_set_no_hosts_fallback"
-extern void __res_set_no_hosts_fallback(void);
-#pragma weak __res_set_no_hosts_fallback
+#define RES_SET_NO_HOSTS_FALLBACK "__joy_res_set_no_hosts_fallback"
+extern void __joy_res_set_no_hosts_fallback(void);
-#define RES_UNSET_NO_HOSTS_FALLBACK "__res_unset_no_hosts_fallback"
-extern void __res_unset_no_hosts_fallback(void);
-#pragma weak __res_unset_no_hosts_fallback
+#define RES_UNSET_NO_HOSTS_FALLBACK "__joy_res_unset_no_hosts_fallback"
+extern void __joy_res_unset_no_hosts_fallback(void);
#define RES_GET_RES "__res_get_res"
extern struct __res_state *__res_get_res(void);
-#pragma weak __res_get_res
#define RES_ENABLE_MT "__res_enable_mt"
extern int __res_enable_mt(void);
-#pragma weak __res_enable_mt
#define RES_DISABLE_MT "__res_disable_mt"
extern int __res_disable_mt(void);
-#pragma weak __res_disable_mt
#define RES_GET_H_ERRNO "__res_get_h_errno"
extern int *__res_get_h_errno();
-#pragma weak __res_get_h_errno
-#define __H_ERRNO "__h_errno"
-extern int *__h_errno(void);
-#pragma weak __h_errno
+#define __H_ERRNO "__joy_h_errno"
+extern int *__joy_h_errno(void);
-#define RES_OVERRIDE_RETRY "__res_override_retry"
-extern int __res_override_retry(int);
-#pragma weak __res_override_retry
+#define RES_OVERRIDE_RETRY "__joy_res_override_retry"
+extern int __joy_res_override_retry(int);
static void __fallback_set_no_hosts(void);
-static int *__fallback_h_errno(void);
-static int __fallback_override_retry(int);
static int __is_mt_safe(void);
void (*set_no_hosts_fallback)(void) = __fallback_set_no_hosts;
void (*unset_no_hosts_fallback)(void) = __fallback_set_no_hosts;
struct __res_state *(*set_res_retry)() = 0;
-int (*enable_mt)() = 0;
-int (*disable_mt)() = 0;
-int *(*get_h_errno)(void) = 0;
-int (*override_retry)(int) = 0;
+int (*enable_mt)() = __is_mt_safe;
+int (*disable_mt)() = __is_mt_safe;
+int *(*get_h_errno)(void) = __joy_h_errno;
+int (*override_retry)(int) = __joy_res_override_retry;
/* Usually set from the Makefile */
#ifndef NSS_DNS_LIBRESOLV
@@ -106,91 +96,12 @@ extern int h_errno;
mutex_t one_lane = DEFAULTMUTEX;
+/* Because we link against libresolv_joy.so.2, this is relatively easy. */
void
_nss_dns_init(void)
{
- void *reslib, (*f_void_ptr)();
-
- /* If no libresolv library, then load one */
- if (res_gethostbyname == 0) {
- if ((reslib =
- dlopen(NSS_DNS_LIBRESOLV, RTLD_LAZY|RTLD_GLOBAL)) != 0) {
- /* Turn off /etc/hosts fall back in libresolv */
- if ((f_void_ptr = (void (*)(void))dlsym(reslib,
- RES_SET_NO_HOSTS_FALLBACK)) != 0) {
- set_no_hosts_fallback = f_void_ptr;
- }
- if ((f_void_ptr = (void (*)(void))dlsym(reslib,
- RES_SET_NO_HOSTS_FALLBACK)) != 0) {
- unset_no_hosts_fallback = f_void_ptr;
- }
- /* Set number of resolver retries */
- if ((override_retry = (int (*)(int))dlsym(reslib,
- RES_OVERRIDE_RETRY)) == 0) {
- set_res_retry =
- (struct __res_state *(*)(void))dlsym(reslib,
- RES_GET_RES);
- override_retry = __fallback_override_retry;
- }
- /*
- * Select h_errno retrieval function. A BIND 8.2.2
- * libresolv.so.2 will have __h_errno, a BIND 8.1.2
- * one will have __res_get_h_errno, and other
- * versions may have nothing at all.
- *
- * Also try to bind to the relevant MT enable/disable
- * functions which are also dependent on the version
- * of the BIND libresolv.so.2 being used.
- */
- if ((get_h_errno = (int *(*)(void))dlsym(reslib,
- __H_ERRNO)) != 0) {
- /* BIND 8.2.2 libresolv.so.2 is MT safe. */
- enable_mt = __is_mt_safe;
- disable_mt = __is_mt_safe;
- } else {
- if ((get_h_errno =
- (int *(*)(void))dlsym(reslib,
- RES_GET_H_ERRNO)) == 0) {
- get_h_errno = __fallback_h_errno;
- }
- /*
- * Pre-BIND 8.2.2 was not MT safe. Try to
- * bind the MT enable/disable functions.
- */
- if ((enable_mt = (int (*)(void))dlsym(reslib,
- RES_ENABLE_MT)) != 0 &&
- (disable_mt = (int (*)(void))dlsym(reslib,
- RES_DISABLE_MT)) == 0) {
- enable_mt = 0;
- }
- }
- }
- } else {
- /* Libresolv already loaded */
- if ((f_void_ptr = __res_set_no_hosts_fallback) != 0) {
- set_no_hosts_fallback = f_void_ptr;
- }
- if ((f_void_ptr = __res_unset_no_hosts_fallback) != 0) {
- unset_no_hosts_fallback = f_void_ptr;
- }
- if ((override_retry = __res_override_retry) == 0) {
- set_res_retry = __res_get_res;
- override_retry = __fallback_override_retry;
- }
- if ((get_h_errno = __h_errno) == 0 &&
- (get_h_errno = __res_get_h_errno) == 0) {
- get_h_errno = __fallback_h_errno;
- }
- if (get_h_errno == __h_errno) {
- enable_mt = __is_mt_safe;
- disable_mt = __is_mt_safe;
- } else {
- if ((enable_mt = __res_enable_mt) != 0 &&
- (disable_mt = __res_disable_mt) == 0) {
- enable_mt = 0;
- }
- }
- }
+ enable_mt = __is_mt_safe;
+ disable_mt = __is_mt_safe;
}
@@ -228,36 +139,6 @@ __is_mt_safe(void) {
}
-/*
- * Return pointer to the global h_errno variable
- */
-static int *
-__fallback_h_errno(void) {
- return (&h_errno);
-}
-
-
-/*
- * This function is called when the resolver library doesn't provide its
- * own function to establish an override retry. If we can get a pointer
- * to the per-thread _res (i.e., set_res_retry != 0), we set the retries
- * directly, and return the previous number of retries. Otherwise, there's
- * nothing to do.
- */
-static int
-__fallback_override_retry(int retry) {
- struct __res_state *res;
- int old_retry = 0;
-
- if (set_res_retry != 0) {
- res = set_res_retry();
- old_retry = res->retry;
- res->retry = retry;
- }
- return (old_retry);
-}
-
-
static void
__fallback_set_no_hosts(void) {
}
diff --git a/usr/src/lib/nsswitch/dns/common/gethostent.c b/usr/src/lib/nsswitch/dns/common/gethostent.c
index 648ea8ba01..d321dd24c6 100644
--- a/usr/src/lib/nsswitch/dns/common/gethostent.c
+++ b/usr/src/lib/nsswitch/dns/common/gethostent.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* gethostent.c
*
@@ -53,12 +51,6 @@ static struct hostent *_gethostbyaddr(int *h_errnop, const char *addr,
int len, int type);
struct hostent *_nss_dns_gethostbyname2(int *h_errnop, const char *name);
-#pragma weak res_gethostbyname
-#pragma weak res_gethostbyname2
-#pragma weak res_gethostbyaddr
-#pragma weak res_sethostent
-#pragma weak res_endhostent
-
nss_backend_t *_nss_dns_constr(dns_backend_op_t ops[], int n_ops);
nss_status_t __nss_dns_getbyaddr(dns_backend_ptr_t, void *);
diff --git a/usr/src/lib/nsswitch/dns/common/gethostent6.c b/usr/src/lib/nsswitch/dns/common/gethostent6.c
index ee85832073..f3efc4eae6 100644
--- a/usr/src/lib/nsswitch/dns/common/gethostent6.c
+++ b/usr/src/lib/nsswitch/dns/common/gethostent6.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* This is the DNS backend for IPv6 addresses.
* getbyname() is a local routine, but getbyaddr() actually shares the
@@ -50,8 +48,6 @@
*/
-#pragma weak res_endhostent
-
extern struct hostent *_gethostbyname(int *, const char *);
extern struct hostent *_nss_dns_gethostbyname2(int *, const char *);
diff --git a/usr/src/lib/pkcs11/pkcs11_tpm/Makefile.com b/usr/src/lib/pkcs11/pkcs11_tpm/Makefile.com
index 020051c977..7345ddc892 100644
--- a/usr/src/lib/pkcs11/pkcs11_tpm/Makefile.com
+++ b/usr/src/lib/pkcs11/pkcs11_tpm/Makefile.com
@@ -73,7 +73,7 @@ TSSLIB=-L$(TSPILIBDIR)
TSSLIB64=-L$(TSPILIBDIR)/$(MACH64)
TSSINC=-I$(TSPIINCDIR)
-LDLIBS += $(TSSLIB) -L$(ADJUNCT_PROTO)/lib -lc -luuid -lmd -ltspi -lcrypto
+LDLIBS += $(TSSLIB) -L$(ADJUNCT_PROTO)/lib -lc -luuid -lmd -ltspi -lsunw_crypto
CPPFLAGS += -xCC -D_POSIX_PTHREAD_SEMANTICS $(TSSINC)
CPPFLAGS64 += $(CPPFLAGS)
C99MODE= $(C99_ENABLE)
diff --git a/usr/src/lib/pysolaris/Makefile.com b/usr/src/lib/pysolaris/Makefile.com
index 7423665381..05eb7981d3 100644
--- a/usr/src/lib/pysolaris/Makefile.com
+++ b/usr/src/lib/pysolaris/Makefile.com
@@ -43,6 +43,7 @@ C99LMODE= -Xc99=%all
LIBS = $(DYNLIB)
LDLIBS += -lc -lsec -lidmap -lpython$(PYTHON_VERSION)
CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(ADJUNCT_PROTO)/usr/include/python2.6
CERRWARN += -_gcc=-Wno-unused-variable
CPPFLAGS += -I$(ADJUNCT_PROTO)/usr/include/python$(PYTHON_VERSION)
diff --git a/usr/src/lib/scsi/libscsi/common/libscsi.h b/usr/src/lib/scsi/libscsi/common/libscsi.h
index 4d57d1299c..5904217fc1 100644
--- a/usr/src/lib/scsi/libscsi/common/libscsi.h
+++ b/usr/src/lib/scsi/libscsi/common/libscsi.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#ifndef _LIBSCSI_H
@@ -97,6 +98,7 @@ typedef struct libscsi_engine_ops {
void (*lseo_close)(libscsi_hdl_t *, void *);
int (*lseo_exec)(libscsi_hdl_t *, void *, libscsi_action_t *);
void (*lseo_target_name)(libscsi_hdl_t *, void *, char *, size_t);
+ int (*lseo_max_transfer)(libscsi_hdl_t *, void *, size_t *);
} libscsi_engine_ops_t;
typedef struct libscsi_engine {
@@ -116,6 +118,7 @@ extern libscsi_hdl_t *libscsi_get_handle(libscsi_target_t *);
extern const char *libscsi_vendor(libscsi_target_t *);
extern const char *libscsi_product(libscsi_target_t *);
extern const char *libscsi_revision(libscsi_target_t *);
+extern int libscsi_max_transfer(libscsi_target_t *, size_t *);
extern libscsi_errno_t libscsi_errno(libscsi_hdl_t *);
extern const char *libscsi_errmsg(libscsi_hdl_t *);
@@ -125,8 +128,11 @@ extern libscsi_errno_t libscsi_errcode(const char *);
extern libscsi_action_t *libscsi_action_alloc(libscsi_hdl_t *, spc3_cmd_t,
uint_t, void *, size_t);
+extern libscsi_action_t *libscsi_action_alloc_vendor(libscsi_hdl_t *,
+ spc3_cmd_t, size_t, uint_t, void *, size_t);
extern sam4_status_t libscsi_action_get_status(const libscsi_action_t *);
extern void libscsi_action_set_timeout(libscsi_action_t *, uint32_t);
+extern size_t libscsi_action_get_cdblen(const libscsi_action_t *);
extern uint32_t libscsi_action_get_timeout(const libscsi_action_t *);
extern uint_t libscsi_action_get_flags(const libscsi_action_t *);
extern uint8_t *libscsi_action_get_cdb(const libscsi_action_t *);
diff --git a/usr/src/lib/scsi/libscsi/common/scsi_engine.c b/usr/src/lib/scsi/libscsi/common/scsi_engine.c
index 3c6d5ecee9..dc7a7af5c1 100644
--- a/usr/src/lib/scsi/libscsi/common/scsi_engine.c
+++ b/usr/src/lib/scsi/libscsi/common/scsi_engine.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#include <sys/types.h>
@@ -265,6 +266,18 @@ libscsi_action_get_flags(const libscsi_action_t *ap)
}
/*
+ * Return the length of the CDB buffer associated with this action. Never
+ * fails.
+ */
+size_t
+libscsi_action_get_cdblen(const libscsi_action_t *ap)
+{
+ const libscsi_action_impl_t *aip = (const libscsi_action_impl_t *)ap;
+
+ return (aip->lsai_cdb_len);
+}
+
+/*
* Returns the address of the action's CDB. The CDB buffer is guaranteed to
* be large enough to hold the complete CDB for the command specified when the
* action was allocated. Therefore, changing the command/opcode portion of
@@ -469,11 +482,11 @@ libscsi_action_set_senselen(libscsi_action_t *ap, size_t len)
* If cmd is SPC3_CMD_REQUEST_SENSE, this flag must be clear.
*/
libscsi_action_t *
-libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
- void *buf, size_t buflen)
+libscsi_action_alloc_vendor(libscsi_hdl_t *hp, spc3_cmd_t cmd, size_t cdbsz,
+ uint_t flags, void *buf, size_t buflen)
{
libscsi_action_impl_t *aip;
- size_t cdbsz, sz;
+ size_t sz;
ptrdiff_t off;
/*
@@ -492,14 +505,14 @@ libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
"in order to use a buffer");
return (NULL);
}
- if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) {
- (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense "
- "flag not allowed for request sense command");
+
+ if (cdbsz == 0) {
+ (void) libscsi_error(hp, ESCSI_BADLENGTH, "the supplied CDB "
+ "buffer size has an invalid length, it must be non-zero.");
return (NULL);
}
- if ((sz = cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0)
- return (NULL);
+ sz = cdbsz;
/*
* If the caller has asked for a buffer but has not provided one, we
@@ -549,6 +562,25 @@ libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
return ((libscsi_action_t *)aip);
}
+libscsi_action_t *
+libscsi_action_alloc(libscsi_hdl_t *hp, spc3_cmd_t cmd, uint_t flags,
+ void *buf, size_t buflen)
+{
+ size_t cdbsz;
+
+ if (cmd == SPC3_CMD_REQUEST_SENSE && (flags & LIBSCSI_AF_RQSENSE)) {
+ (void) libscsi_error(hp, ESCSI_BADFLAGS, "request sense "
+ "flag not allowed for request sense command");
+ return (NULL);
+ }
+
+ if ((cdbsz = libscsi_cmd_cdblen(hp, cmd)) == 0)
+ return (NULL);
+
+ return (libscsi_action_alloc_vendor(hp, cmd, cdbsz, flags, buf,
+ buflen));
+}
+
void
libscsi_action_free(libscsi_action_t *ap)
{
@@ -616,3 +648,16 @@ libscsi_exec(libscsi_action_t *ap, libscsi_target_t *tp)
return (ret);
}
+
+int
+libscsi_max_transfer(libscsi_target_t *tp, size_t *sizep)
+{
+ libscsi_hdl_t *hp = tp->lst_hdl;
+ if (tp->lst_engine->lse_ops->lseo_max_transfer == NULL) {
+ return (libscsi_error(hp, ESCSI_NOTSUP, "max transfer "
+ "request not supported by engine"));
+ }
+
+ return (tp->lst_engine->lse_ops->lseo_max_transfer(hp, tp->lst_priv,
+ sizep));
+}
diff --git a/usr/src/lib/scsi/libscsi/libscsi_api.map b/usr/src/lib/scsi/libscsi/libscsi_api.map
index 72efb3a2de..b44e80c611 100644
--- a/usr/src/lib/scsi/libscsi/libscsi_api.map
+++ b/usr/src/lib/scsi/libscsi/libscsi_api.map
@@ -21,6 +21,7 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, Joyent, Inc.
#
$mapfile_version 2
@@ -40,6 +41,7 @@ SYMBOL_SCOPE {
libscsi_action_get_timeout { TYPE = FUNCTION; FLAGS = extern };
libscsi_action_get_flags { TYPE = FUNCTION; FLAGS = extern };
libscsi_action_get_cdb { TYPE = FUNCTION; FLAGS = extern };
+ libscsi_action_get_cdblen { TYPE = FUNCTION; FLAGS = extern };
libscsi_action_get_buffer { TYPE = FUNCTION; FLAGS = extern };
libscsi_action_get_sense { TYPE = FUNCTION; FLAGS = extern };
libscsi_action_set_status { TYPE = FUNCTION; FLAGS = extern };
diff --git a/usr/src/lib/scsi/libscsi/mapfile-vers b/usr/src/lib/scsi/libscsi/mapfile-vers
index 7e0d8e251c..0b92a7412c 100644
--- a/usr/src/lib/scsi/libscsi/mapfile-vers
+++ b/usr/src/lib/scsi/libscsi/mapfile-vers
@@ -21,6 +21,7 @@
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, Joyent, Inc.
#
#
@@ -46,11 +47,13 @@ SYMBOL_VERSION SUNWprivate_1.1 {
libscsi_open;
libscsi_close;
libscsi_action_alloc;
+ libscsi_action_alloc_vendor;
libscsi_action_get_status;
libscsi_action_set_status;
libscsi_action_get_timeout;
libscsi_action_set_timeout;
libscsi_action_get_cdb;
+ libscsi_action_get_cdblen;
libscsi_action_get_flags;
libscsi_action_get_buffer;
libscsi_action_get_sense;
@@ -71,6 +74,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
libscsi_vendor;
libscsi_product;
libscsi_revision;
+ libscsi_max_transfer;
libscsi_get_handle;
libscsi_alloc;
diff --git a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c
index 06cdb0b339..bd24c0fbfb 100644
--- a/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c
+++ b/usr/src/lib/scsi/plugins/scsi/engines/uscsi/uscsi.c
@@ -22,10 +22,10 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2017, Joyent, Inc.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/scsi/impl/uscsi.h>
#include <sys/scsi/generic/commands.h>
@@ -111,10 +111,10 @@ xlate_flags(libscsi_hdl_t *hp, uint_t flags, int *uf)
f |= USCSI_DIAGNOSE;
break;
case LIBSCSI_AF_ISOLATE:
- f = USCSI_ISOLATE;
+ f |= USCSI_ISOLATE;
break;
case LIBSCSI_AF_RQSENSE:
- f = USCSI_RQENABLE;
+ f |= USCSI_RQENABLE;
break;
default:
return (libscsi_error(hp, ESCSI_BOGUSFLAGS,
@@ -150,7 +150,7 @@ uscsi_exec(libscsi_hdl_t *hp, void *private, libscsi_action_t *ap)
cmd.uscsi_timeout = (short)libscsi_action_get_timeout(ap);
cmd.uscsi_cdb = (caddr_t)cp;
- cmd.uscsi_cdblen = libscsi_cmd_cdblen(hp, *cp);
+ cmd.uscsi_cdblen = libscsi_action_get_cdblen(ap);
if (cmd.uscsi_cdblen == 0)
return (-1);
@@ -214,11 +214,43 @@ uscsi_target_name(libscsi_hdl_t *hp, void *private, char *buf, size_t len)
(void) snprintf(buf, len, "%s", dp->dev);
}
+static int
+uscsi_max_transfer(libscsi_hdl_t *hp, void *private, size_t *sizep)
+{
+ uscsi_xfer_t xfer;
+ struct uscsi_dev *dp = (struct uscsi_dev *)private;
+
+ if (ioctl(dp->fd, USCSIMAXXFER, &xfer) < 0) {
+ ASSERT(errno != EFAULT);
+ switch (errno) {
+ case EINVAL:
+ return (libscsi_error(hp, ESCSI_BADCMD, "internal "
+ "uscsi error"));
+ case EPERM:
+ return (libscsi_error(hp, ESCSI_PERM, "insufficient "
+ "privileges "));
+ case ENOTTY:
+ return (libscsi_error(hp, ESCSI_NOTSUP, "max transfer "
+ "request not supported on device"));
+ default:
+ return (libscsi_error(hp, ESCSI_SYS, "uscsi ioctl "
+ "failed: %s", strerror(errno)));
+ }
+ }
+
+ if (xfer > SIZE_MAX)
+ xfer = SIZE_MAX;
+
+ *sizep = (size_t)xfer;
+ return (0);
+}
+
static const libscsi_engine_ops_t uscsi_ops = {
.lseo_open = uscsi_open,
.lseo_close = uscsi_close,
.lseo_exec = uscsi_exec,
- .lseo_target_name = uscsi_target_name
+ .lseo_target_name = uscsi_target_name,
+ .lseo_max_transfer = uscsi_max_transfer
};
static const libscsi_engine_t uscsi_engine = {
diff --git a/usr/src/lib/varpd/Makefile b/usr/src/lib/varpd/Makefile
new file mode 100644
index 0000000000..daa849572e
--- /dev/null
+++ b/usr/src/lib/varpd/Makefile
@@ -0,0 +1,33 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+SUBDIRS = libvarpd .WAIT direct files svp
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+check := TARGET = check
+install := TARGET = install
+install_h := TARGET = install_h
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install install_h check lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/varpd/Makefile.plugin b/usr/src/lib/varpd/Makefile.plugin
new file mode 100644
index 0000000000..48f188500c
--- /dev/null
+++ b/usr/src/lib/varpd/Makefile.plugin
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+ROOTLIBDIR = $(ROOT)/usr/lib/varpd
+ROOTLIBDIR64 = $(ROOT)/usr/lib/varpd/$(MACH64)
+
+MAPFILES += ../../libvarpd/common/mapfile-plugin
diff --git a/usr/src/lib/varpd/direct/Makefile b/usr/src/lib/varpd/direct/Makefile
new file mode 100644
index 0000000000..275f07bf8b
--- /dev/null
+++ b/usr/src/lib/varpd/direct/Makefile
@@ -0,0 +1,40 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/direct/Makefile.com b/usr/src/lib/varpd/direct/Makefile.com
new file mode 100644
index 0000000000..4072c9a0ab
--- /dev/null
+++ b/usr/src/lib/varpd/direct/Makefile.com
@@ -0,0 +1,38 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd_direct.a
+VERS = .1
+OBJECTS = libvarpd_direct.o
+
+include ../../../Makefile.lib
+include ../../Makefile.plugin
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lumem -lnvpair -lnsl
+CPPFLAGS += -I../common
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/direct/amd64/Makefile b/usr/src/lib/varpd/direct/amd64/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/direct/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/direct/common/libvarpd_direct.c b/usr/src/lib/varpd/direct/common/libvarpd_direct.c
new file mode 100644
index 0000000000..018cdf641c
--- /dev/null
+++ b/usr/src/lib/varpd/direct/common/libvarpd_direct.c
@@ -0,0 +1,411 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Point to point plug-in for varpd.
+ *
+ * This plugin implements a simple point to point plugin for a packet. It
+ * represents the traditional tunnel, just in overlay form. As such, the only
+ * properties it needs are those to determine where to send everything. At this
+ * time, we don't allow a mulicast address; however, there's no reason that the
+ * direct plugin shouldn't in theory support multicast, though when implementing
+ * it the best path will become clear.
+ *
+ * In general this module has been designed to make it easy to support a
+ * destination of either IP or IP and port; however, we restrict it to the
+ * latter as we don't currently have an implementation that would allow us to
+ * test that.
+ */
+
+#include <libvarpd_provider.h>
+#include <umem.h>
+#include <errno.h>
+#include <thread.h>
+#include <synch.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libnvpair.h>
+
+typedef struct varpd_direct {
+ overlay_plugin_dest_t vad_dest; /* RO */
+ mutex_t vad_lock; /* Protects the rest */
+ boolean_t vad_hip;
+ boolean_t vad_hport;
+ struct in6_addr vad_ip;
+ uint16_t vad_port;
+} varpd_direct_t;
+
+static const char *varpd_direct_props[] = {
+ "direct/dest_ip",
+ "direct/dest_port"
+};
+
+static boolean_t
+varpd_direct_valid_dest(overlay_plugin_dest_t dest)
+{
+ if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (B_FALSE);
+
+ if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static int
+varpd_direct_create(varpd_provider_handle_t *hdl, void **outp,
+ overlay_plugin_dest_t dest)
+{
+ int ret;
+ varpd_direct_t *vdp;
+
+ if (varpd_direct_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
+ if (vdp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+
+ vdp->vad_dest = dest;
+ vdp->vad_hip = B_FALSE;
+ vdp->vad_hport = B_FALSE;
+ *outp = vdp;
+ return (0);
+}
+
+static int
+varpd_direct_start(void *arg)
+{
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hip == B_FALSE ||((vdp->vad_dest & OVERLAY_PLUGIN_D_IP) &&
+ vdp->vad_hport == B_FALSE)) {
+ mutex_exit(&vdp->vad_lock);
+ return (EAGAIN);
+ }
+ mutex_exit(&vdp->vad_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+varpd_direct_stop(void *arg)
+{
+}
+
+static void
+varpd_direct_destroy(void *arg)
+{
+ varpd_direct_t *vdp = arg;
+
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+}
+
+static int
+varpd_direct_default(void *arg, overlay_target_point_t *otp)
+{
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ bcopy(&vdp->vad_ip, &otp->otp_ip, sizeof (struct in6_addr));
+ otp->otp_port = vdp->vad_port;
+ mutex_exit(&vdp->vad_lock);
+
+ return (VARPD_LOOKUP_OK);
+}
+
+static int
+varpd_direct_nprops(void *arg, uint_t *nprops)
+{
+ const varpd_direct_t *vdp = arg;
+
+ *nprops = 0;
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ *nprops += 1;
+
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_IP)
+ *nprops += 1;
+
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_PORT)
+ *nprops += 1;
+
+ assert(*nprops == 1 || *nprops == 2);
+
+ return (0);
+}
+
+static int
+varpd_direct_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
+{
+ varpd_direct_t *vdp = arg;
+
+ /*
+ * Because we only support IP + port combos right now, prop 0 should
+ * always be the IP. We don't support a port without an IP.
+ */
+ assert(vdp->vad_dest & OVERLAY_PLUGIN_D_IP);
+ if (propid == 0) {
+ libvarpd_prop_set_name(vph, varpd_direct_props[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_IP);
+ libvarpd_prop_set_nodefault(vph);
+ return (0);
+ }
+
+ if (propid == 1 && vdp->vad_dest & OVERLAY_PLUGIN_D_PORT) {
+ libvarpd_prop_set_name(vph, varpd_direct_props[1]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
+ libvarpd_prop_set_nodefault(vph);
+ libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
+{
+ varpd_direct_t *vdp = arg;
+
+ /* direct/dest_ip */
+ if (strcmp(pname, varpd_direct_props[0]) == 0) {
+ if (*sizep < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hip == B_FALSE) {
+ *sizep = 0;
+ } else {
+ bcopy(&vdp->vad_ip, buf, sizeof (struct in6_addr));
+ *sizep = sizeof (struct in6_addr);
+ }
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ /* direct/dest_port */
+ if (strcmp(pname, varpd_direct_props[1]) == 0) {
+ uint64_t val;
+
+ if (*sizep < sizeof (uint64_t))
+ return (EOVERFLOW);
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hport == B_FALSE) {
+ *sizep = 0;
+ } else {
+ val = vdp->vad_port;
+ bcopy(&val, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ }
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_setprop(void *arg, const char *pname, const void *buf,
+ const uint32_t size)
+{
+ varpd_direct_t *vdp = arg;
+
+ /* direct/dest_ip */
+ if (strcmp(pname, varpd_direct_props[0]) == 0) {
+ const struct in6_addr *ipv6 = buf;
+
+ if (size < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+
+ if (IN6_IS_ADDR_V4COMPAT(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_6TO4(ipv6))
+ return (EINVAL);
+
+ mutex_enter(&vdp->vad_lock);
+ bcopy(buf, &vdp->vad_ip, sizeof (struct in6_addr));
+ vdp->vad_hip = B_TRUE;
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ /* direct/dest_port */
+ if (strcmp(pname, varpd_direct_props[1]) == 0) {
+ const uint64_t *valp = buf;
+ if (size < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ if (*valp == 0 || *valp > UINT16_MAX)
+ return (EINVAL);
+
+ mutex_enter(&vdp->vad_lock);
+ vdp->vad_port = (uint16_t)*valp;
+ vdp->vad_hport = B_TRUE;
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_save(void *arg, nvlist_t *nvp)
+{
+ int ret;
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hport == B_TRUE) {
+ if ((ret = nvlist_add_uint16(nvp, varpd_direct_props[1],
+ vdp->vad_port)) != 0) {
+ mutex_exit(&vdp->vad_lock);
+ return (ret);
+ }
+ }
+
+ if (vdp->vad_hip == B_TRUE) {
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, &vdp->vad_ip, buf, sizeof (buf)) ==
+ NULL)
+ abort();
+ if ((ret = nvlist_add_string(nvp, varpd_direct_props[0],
+ buf)) != 0) {
+ mutex_exit(&vdp->vad_lock);
+ return (ret);
+ }
+ }
+ mutex_exit(&vdp->vad_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+varpd_direct_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
+ overlay_plugin_dest_t dest, void **outp)
+{
+ int ret;
+ char *ipstr;
+ varpd_direct_t *vdp;
+
+ if (varpd_direct_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
+ if (vdp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+
+ if ((ret = nvlist_lookup_uint16(nvp, varpd_direct_props[1],
+ &vdp->vad_port)) != 0) {
+ if (ret != ENOENT) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+ vdp->vad_hport = B_FALSE;
+ } else {
+ vdp->vad_hport = B_TRUE;
+ }
+
+ if ((ret = nvlist_lookup_string(nvp, varpd_direct_props[0],
+ &ipstr)) != 0) {
+ if (ret != ENOENT) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+ vdp->vad_hip = B_FALSE;
+ } else {
+ ret = inet_pton(AF_INET6, ipstr, &vdp->vad_ip);
+ /*
+ * inet_pton is only defined to return -1 with errno set to
+ * EAFNOSUPPORT, which really, shouldn't happen.
+ */
+ if (ret == -1) {
+ assert(errno == EAFNOSUPPORT);
+ abort();
+ }
+ if (ret == 0) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (EINVAL);
+ }
+ }
+
+ *outp = vdp;
+ return (0);
+}
+
+static const varpd_plugin_ops_t varpd_direct_ops = {
+ 0,
+ varpd_direct_create,
+ varpd_direct_start,
+ varpd_direct_stop,
+ varpd_direct_destroy,
+ varpd_direct_default,
+ NULL,
+ varpd_direct_nprops,
+ varpd_direct_propinfo,
+ varpd_direct_getprop,
+ varpd_direct_setprop,
+ varpd_direct_save,
+ varpd_direct_restore
+};
+
+#pragma init(varpd_direct_init)
+static void
+varpd_direct_init(void)
+{
+ int err;
+ varpd_plugin_register_t *vpr;
+
+ vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
+ if (vpr == NULL)
+ return;
+
+ vpr->vpr_mode = OVERLAY_TARGET_POINT;
+ vpr->vpr_name = "direct";
+ vpr->vpr_ops = &varpd_direct_ops;
+ (void) libvarpd_plugin_register(vpr);
+ libvarpd_plugin_free(vpr);
+}
diff --git a/usr/src/lib/varpd/direct/common/llib-lvarpd_direct b/usr/src/lib/varpd/direct/common/llib-lvarpd_direct
new file mode 100644
index 0000000000..03c34f4fcb
--- /dev/null
+++ b/usr/src/lib/varpd/direct/common/llib-lvarpd_direct
@@ -0,0 +1,18 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
diff --git a/usr/src/lib/varpd/direct/common/mapfile-vers b/usr/src/lib/varpd/direct/common/mapfile-vers
new file mode 100644
index 0000000000..6b7c5a5067
--- /dev/null
+++ b/usr/src/lib/varpd/direct/common/mapfile-vers
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/direct/i386/Makefile b/usr/src/lib/varpd/direct/i386/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/direct/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/direct/sparc/Makefile b/usr/src/lib/varpd/direct/sparc/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/direct/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/direct/sparcv9/Makefile b/usr/src/lib/varpd/direct/sparcv9/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/direct/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/files/Makefile b/usr/src/lib/varpd/files/Makefile
new file mode 100644
index 0000000000..275f07bf8b
--- /dev/null
+++ b/usr/src/lib/varpd/files/Makefile
@@ -0,0 +1,40 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/files/Makefile.com b/usr/src/lib/varpd/files/Makefile.com
new file mode 100644
index 0000000000..1f6a7c03b1
--- /dev/null
+++ b/usr/src/lib/varpd/files/Makefile.com
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd_files.a
+VERS = .1
+OBJECTS = libvarpd_files.o \
+ libvarpd_files_json.o
+
+include ../../../Makefile.lib
+include ../../Makefile.plugin
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lumem -lnvpair -lsocket -lnsl -lcmdutils
+CPPFLAGS += -I../common
+
+LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
+LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/files/amd64/Makefile b/usr/src/lib/varpd/files/amd64/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/files/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files.c b/usr/src/lib/varpd/files/common/libvarpd_files.c
new file mode 100644
index 0000000000..812919a07d
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files.c
@@ -0,0 +1,605 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * Files based plug-in for varpd
+ *
+ * This is a dynamic varpd plug-in that has a static backing store. It's really
+ * nothing more than a glorified version of /etc/ethers, though it facilitiates
+ * a bit more. The files module allows for the full set of mappings to be fixed
+ * at creation time. In addition, it also provides support for proxying ARP,
+ * NDP, and DHCP.
+ *
+ * At this time, the plugin requires that the destination type involve both an
+ * IP address and a port; however, there's no reason that this cannot be made
+ * more flexible as we have additional encapsulation algorithms that support it.
+ * The plug-in only has a single property, which is the location of the JSON
+ * file. The JSON file itself looks something like:
+ *
+ * {
+ * "aa:bb:cc:dd:ee:ff": {
+ * "arp": "10.23.69.1",
+ * "ndp": "2600:3c00::f03c:91ff:fe96:a264",
+ * "ip": "192.168.1.1",
+ * "port": 8080
+ * },
+ * ...
+ * }
+ */
+
+#include <libvarpd_provider.h>
+#include <umem.h>
+#include <errno.h>
+#include <thread.h>
+#include <synch.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ethernet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <libvarpd_files_json.h>
+
+typedef struct varpd_files {
+ overlay_plugin_dest_t vaf_dest; /* RO */
+ varpd_provider_handle_t *vaf_hdl; /* RO */
+ char *vaf_path; /* WO */
+ nvlist_t *vaf_nvl; /* WO */
+ uint64_t vaf_nmisses; /* Atomic */
+ uint64_t vaf_narp; /* Atomic */
+} varpd_files_t;
+
+static const char *varpd_files_props[] = {
+ "files/config"
+};
+
+static boolean_t
+varpd_files_valid_dest(overlay_plugin_dest_t dest)
+{
+ if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (B_FALSE);
+
+ if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+static int
+varpd_files_create(varpd_provider_handle_t *hdl, void **outp,
+ overlay_plugin_dest_t dest)
+{
+ varpd_files_t *vaf;
+
+ if (varpd_files_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
+ if (vaf == NULL)
+ return (ENOMEM);
+
+ bzero(vaf, sizeof (varpd_files_t));
+ vaf->vaf_dest = dest;
+ vaf->vaf_path = NULL;
+ vaf->vaf_nvl = NULL;
+ vaf->vaf_hdl = hdl;
+ *outp = vaf;
+ return (0);
+}
+
+static int
+varpd_files_normalize_nvlist(varpd_files_t *vaf, nvlist_t *nvl)
+{
+ int ret;
+ nvlist_t *out;
+ nvpair_t *pair;
+
+ if ((ret = nvlist_alloc(&out, NV_UNIQUE_NAME, 0)) != 0)
+ return (ret);
+
+ for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair)) {
+ char *name, fname[ETHERADDRSTRL];
+ nvlist_t *data;
+ struct ether_addr ether, *e;
+ e = &ether;
+
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ name = nvpair_name(pair);
+ if ((ret = nvpair_value_nvlist(pair, &data)) != 0) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ if (ether_aton_r(name, e) == NULL) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ if (ether_ntoa_r(e, fname) == NULL) {
+ nvlist_free(out);
+ return (ENOMEM);
+ }
+
+ if ((ret = nvlist_add_nvlist(out, fname, data)) != 0) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+ }
+
+ vaf->vaf_nvl = out;
+ return (0);
+}
+
+static int
+varpd_files_start(void *arg)
+{
+ int fd, ret;
+ void *maddr;
+ struct stat st;
+ nvlist_t *nvl;
+ varpd_files_t *vaf = arg;
+
+ if (vaf->vaf_path == NULL)
+ return (EAGAIN);
+
+ if ((fd = open(vaf->vaf_path, O_RDONLY)) < 0)
+ return (errno);
+
+ if (fstat(fd, &st) != 0) {
+ ret = errno;
+ if (close(fd) != 0)
+ abort();
+ return (ret);
+ }
+
+ maddr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+ fd, 0);
+ if (maddr == NULL) {
+ ret = errno;
+ if (close(fd) != 0)
+ abort();
+ return (ret);
+ }
+
+ ret = nvlist_parse_json(maddr, st.st_size, &nvl,
+ NVJSON_FORCE_INTEGER, NULL);
+ if (ret == 0) {
+ ret = varpd_files_normalize_nvlist(vaf, nvl);
+ nvlist_free(nvl);
+ }
+ if (munmap(maddr, st.st_size) != 0)
+ abort();
+ if (close(fd) != 0)
+ abort();
+
+ return (ret);
+}
+
+static void
+varpd_files_stop(void *arg)
+{
+ varpd_files_t *vaf = arg;
+
+ nvlist_free(vaf->vaf_nvl);
+ vaf->vaf_nvl = NULL;
+}
+
+static void
+varpd_files_destroy(void *arg)
+{
+ varpd_files_t *vaf = arg;
+
+ assert(vaf->vaf_nvl == NULL);
+ if (vaf->vaf_path != NULL) {
+ umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
+ vaf->vaf_path = NULL;
+ }
+ umem_free(vaf, sizeof (varpd_files_t));
+}
+
+static void
+varpd_files_lookup(void *arg, varpd_query_handle_t *qh,
+ const overlay_targ_lookup_t *otl, overlay_target_point_t *otp)
+{
+ char macstr[ETHERADDRSTRL], *ipstr;
+ nvlist_t *nvl;
+ varpd_files_t *vaf = arg;
+ int32_t port;
+ static const uint8_t bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ /* We don't support a default */
+ if (otl == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_ARP) {
+ libvarpd_plugin_proxy_arp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_IPV6 &&
+ otl->otl_dstaddr[0] == 0x33 &&
+ otl->otl_dstaddr[1] == 0x33) {
+ libvarpd_plugin_proxy_ndp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_IP &&
+ bcmp(otl->otl_dstaddr, bcast, ETHERADDRL) == 0) {
+ char *mac;
+ struct ether_addr a, *addr;
+
+ addr = &a;
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_aton_r(mac, addr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ libvarpd_plugin_proxy_dhcp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_dstaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_int32(nvl, "port", &port) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (port <= 0 || port > UINT16_MAX) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ otp->otp_port = port;
+
+ if (nvlist_lookup_string(nvl, "ip", &ipstr) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ /*
+ * Try to parse it as a v6 address and then if it's not, try to
+ * transform it into a v4 address which we'll then wrap it into a v4
+ * mapped address.
+ */
+ if (inet_pton(AF_INET6, ipstr, &otp->otp_ip) != 1) {
+ uint32_t v4;
+ if (inet_pton(AF_INET, ipstr, &v4) != 1) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ IN6_IPADDR_TO_V4MAPPED(v4, &otp->otp_ip);
+ }
+
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_OK);
+}
+
+/* ARGSUSED */
+static int
+varpd_files_nprops(void *arg, uint_t *nprops)
+{
+ *nprops = 1;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+varpd_files_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
+{
+ if (propid != 0)
+ return (EINVAL);
+
+ libvarpd_prop_set_name(vph, varpd_files_props[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
+ libvarpd_prop_set_nodefault(vph);
+ return (0);
+}
+
+static int
+varpd_files_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
+{
+ varpd_files_t *vaf = arg;
+
+ if (strcmp(pname, varpd_files_props[0]) != 0)
+ return (EINVAL);
+
+ if (vaf->vaf_path != NULL) {
+ size_t len = strlen(vaf->vaf_path) + 1;
+ if (*sizep < len)
+ return (EOVERFLOW);
+ *sizep = len;
+ (void) strlcpy(buf, vaf->vaf_path, *sizep);
+
+ } else {
+ *sizep = 0;
+ }
+
+ return (0);
+}
+
+static int
+varpd_files_setprop(void *arg, const char *pname, const void *buf,
+ const uint32_t size)
+{
+ varpd_files_t *vaf = arg;
+
+ if (strcmp(pname, varpd_files_props[0]) != 0)
+ return (EINVAL);
+
+ if (vaf->vaf_path != NULL)
+ umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
+
+ vaf->vaf_path = umem_alloc(size, UMEM_DEFAULT);
+ if (vaf->vaf_path == NULL)
+ return (ENOMEM);
+ (void) strlcpy(vaf->vaf_path, buf, size);
+ return (0);
+}
+
+static int
+varpd_files_save(void *arg, nvlist_t *nvp)
+{
+ int ret;
+ varpd_files_t *vaf = arg;
+
+ if (vaf->vaf_path == NULL)
+ return (0);
+
+ if ((ret = nvlist_add_string(nvp, varpd_files_props[0],
+ vaf->vaf_path)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_uint64(nvp, "files/vaf_nmisses",
+ vaf->vaf_nmisses)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_uint64(nvp, "files/vaf_narp",
+ vaf->vaf_narp)) != 0)
+ return (ret);
+ return (0);
+}
+
+static int
+varpd_files_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
+ overlay_plugin_dest_t dest, void **outp)
+{
+ varpd_files_t *vaf;
+ char *str;
+ int ret;
+ uint64_t nmisses, narp;
+
+ if (varpd_files_valid_dest(dest) == B_FALSE)
+ return (EINVAL);
+
+ ret = nvlist_lookup_string(nvp, varpd_files_props[0], &str);
+ if (ret != 0 && ret != ENOENT)
+ return (ret);
+ else if (ret == ENOENT)
+ str = NULL;
+
+ if (nvlist_lookup_uint64(nvp, "files/vaf_nmisses", &nmisses) != 0)
+ return (EINVAL);
+ if (nvlist_lookup_uint64(nvp, "files/vaf_narp", &narp) != 0)
+ return (EINVAL);
+
+ vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
+ if (vaf == NULL)
+ return (ENOMEM);
+
+ bzero(vaf, sizeof (varpd_files_t));
+ vaf->vaf_dest = dest;
+ if (str != NULL) {
+ size_t len = strlen(str) + 1;
+ vaf->vaf_path = umem_alloc(len, UMEM_DEFAULT);
+ if (vaf->vaf_path == NULL) {
+ umem_free(vaf, sizeof (varpd_files_t));
+ return (ENOMEM);
+ }
+ (void) strlcpy(vaf->vaf_path, str, len);
+ }
+
+ vaf->vaf_hdl = hdl;
+ *outp = vaf;
+ return (0);
+}
+
+static void
+varpd_files_proxy_arp(void *arg, varpd_arp_handle_t *vah, int kind,
+ const struct sockaddr *sock, uint8_t *out)
+{
+ varpd_files_t *vaf = arg;
+ const struct sockaddr_in *ip;
+ const struct sockaddr_in6 *ip6;
+ nvpair_t *pair;
+
+ if (kind != VARPD_QTYPE_ETHERNET) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (sock->sa_family != AF_INET && sock->sa_family != AF_INET6) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ ip = (const struct sockaddr_in *)sock;
+ ip6 = (const struct sockaddr_in6 *)sock;
+ for (pair = nvlist_next_nvpair(vaf->vaf_nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(vaf->vaf_nvl, pair)) {
+ char *mac, *ipstr;
+ nvlist_t *data;
+ struct in_addr ia;
+ struct in6_addr ia6;
+ struct ether_addr ether, *e;
+ e = &ether;
+
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST)
+ continue;
+
+ mac = nvpair_name(pair);
+ if (nvpair_value_nvlist(pair, &data) != 0)
+ continue;
+
+
+ if (sock->sa_family == AF_INET) {
+ if (nvlist_lookup_string(data, "arp", &ipstr) != 0)
+ continue;
+
+ if (inet_pton(AF_INET, ipstr, &ia) != 1)
+ continue;
+
+ if (bcmp(&ia, &ip->sin_addr,
+ sizeof (struct in_addr)) != 0)
+ continue;
+ } else {
+ if (nvlist_lookup_string(data, "ndp", &ipstr) != 0)
+ continue;
+
+ if (inet_pton(AF_INET6, ipstr, &ia6) != 1)
+ continue;
+
+ if (bcmp(&ia6, &ip6->sin6_addr,
+ sizeof (struct in6_addr)) != 0)
+ continue;
+ }
+
+ if (ether_aton_r(mac, e) == NULL) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ bcopy(e, out, ETHERADDRL);
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_OK);
+ return;
+ }
+
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+}
+
+static void
+varpd_files_proxy_dhcp(void *arg, varpd_dhcp_handle_t *vdh, int type,
+ const overlay_targ_lookup_t *otl, uint8_t *out)
+{
+ varpd_files_t *vaf = arg;
+ nvlist_t *nvl;
+ char macstr[ETHERADDRSTRL], *mac;
+ struct ether_addr a, *addr;
+
+ addr = &a;
+ if (type != VARPD_QTYPE_ETHERNET) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_aton_r(mac, addr) == NULL) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ bcopy(addr, out, ETHERADDRL);
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_OK);
+}
+
+static const varpd_plugin_ops_t varpd_files_ops = {
+ 0,
+ varpd_files_create,
+ varpd_files_start,
+ varpd_files_stop,
+ varpd_files_destroy,
+ NULL,
+ varpd_files_lookup,
+ varpd_files_nprops,
+ varpd_files_propinfo,
+ varpd_files_getprop,
+ varpd_files_setprop,
+ varpd_files_save,
+ varpd_files_restore,
+ varpd_files_proxy_arp,
+ varpd_files_proxy_dhcp
+};
+
+#pragma init(varpd_files_init)
+static void
+varpd_files_init(void)
+{
+ int err;
+ varpd_plugin_register_t *vpr;
+
+ vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
+ if (vpr == NULL)
+ return;
+
+ vpr->vpr_mode = OVERLAY_TARGET_DYNAMIC;
+ vpr->vpr_name = "files";
+ vpr->vpr_ops = &varpd_files_ops;
+ (void) libvarpd_plugin_register(vpr);
+ libvarpd_plugin_free(vpr);
+}
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files_json.c b/usr/src/lib/varpd/files/common/libvarpd_files_json.c
new file mode 100644
index 0000000000..240c84bd77
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files_json.c
@@ -0,0 +1,936 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <strings.h>
+#include <errno.h>
+#include <libnvpair.h>
+#include <sys/ccompile.h>
+
+#include "libvarpd_files_json.h"
+
+typedef enum json_type {
+ JSON_TYPE_NOTHING = 0,
+ JSON_TYPE_STRING = 1,
+ JSON_TYPE_INTEGER,
+ JSON_TYPE_DOUBLE,
+ JSON_TYPE_BOOLEAN,
+ JSON_TYPE_NULL,
+ JSON_TYPE_OBJECT,
+ JSON_TYPE_ARRAY
+} json_type_t;
+
+typedef enum parse_state {
+ PARSE_ERROR = -1,
+ PARSE_DONE = 0,
+ PARSE_REST,
+ PARSE_OBJECT,
+ PARSE_KEY_STRING,
+ PARSE_COLON,
+ PARSE_STRING,
+ PARSE_OBJECT_COMMA,
+ PARSE_ARRAY,
+ PARSE_BAREWORD,
+ PARSE_NUMBER,
+ PARSE_ARRAY_VALUE,
+ PARSE_ARRAY_COMMA
+} parse_state_t;
+
+#define JSON_MARKER ".__json_"
+#define JSON_MARKER_ARRAY JSON_MARKER "array"
+
+typedef struct parse_frame {
+ parse_state_t pf_ps;
+ nvlist_t *pf_nvl;
+
+ char *pf_key;
+ void *pf_value;
+ json_type_t pf_value_type;
+ int pf_array_index;
+
+ struct parse_frame *pf_next;
+} parse_frame_t;
+
+typedef struct state {
+ const char *s_in;
+ unsigned long s_pos;
+ unsigned long s_len;
+
+ parse_frame_t *s_top;
+
+ nvlist_parse_json_flags_t s_flags;
+
+ /*
+ * This string buffer is used for temporary storage by the
+ * "collect_*()" family of functions.
+ */
+ custr_t *s_collect;
+
+ int s_errno;
+ custr_t *s_errstr;
+} state_t;
+
+typedef void (*parse_handler_t)(state_t *);
+
+static void
+movestate(state_t *s, parse_state_t ps)
+{
+ if (s->s_flags & NVJSON_DEBUG) {
+ (void) fprintf(stderr, "nvjson: move state %d -> %d\n",
+ s->s_top->pf_ps, ps);
+ }
+ s->s_top->pf_ps = ps;
+}
+
+static void
+posterror(state_t *s, int erno, const char *error)
+{
+ /*
+ * If the caller wants error messages printed to stderr, do that
+ * first.
+ */
+ if (s->s_flags & NVJSON_ERRORS_TO_STDERR) {
+ (void) fprintf(stderr, "nvjson error (pos %ld, errno %d): %s\n",
+ s->s_pos, erno, error);
+ }
+
+ /*
+ * Try and store the error message for the caller. This may fail if
+ * the error was related to memory pressure, and that condition still
+ * exists.
+ */
+ s->s_errno = erno;
+ if (s->s_errstr != NULL) {
+ (void) custr_append(s->s_errstr, error);
+ }
+
+ movestate(s, PARSE_ERROR);
+}
+
+static int
+pushstate(state_t *s, parse_state_t ps, parse_state_t retps)
+{
+ parse_frame_t *n;
+
+ if (s->s_flags & NVJSON_DEBUG) {
+ (void) fprintf(stderr, "nvjson: push state %d -> %d (ret %d)\n",
+ s->s_top->pf_ps, ps, retps);
+ }
+
+ if ((n = calloc(1, sizeof (*n))) == NULL) {
+ posterror(s, errno, "pushstate calloc failure");
+ return (-1);
+ }
+
+ /*
+ * Store the state we'll return to when popping this
+ * frame:
+ */
+ s->s_top->pf_ps = retps;
+
+ /*
+ * Store the initial state for the new frame, and
+ * put it on top of the stack:
+ */
+ n->pf_ps = ps;
+ n->pf_value_type = JSON_TYPE_NOTHING;
+
+ n->pf_next = s->s_top;
+ s->s_top = n;
+
+ return (0);
+}
+
+static char
+popchar(state_t *s)
+{
+ if (s->s_pos > s->s_len) {
+ return (0);
+ }
+ return (s->s_in[s->s_pos++]);
+}
+
+static char
+peekchar(state_t *s)
+{
+ if (s->s_pos > s->s_len) {
+ return (0);
+ }
+ return (s->s_in[s->s_pos]);
+}
+
+static void
+discard_whitespace(state_t *s)
+{
+ while (isspace(peekchar(s))) {
+ (void) popchar(s);
+ }
+}
+
+static char *escape_pairs[] = {
+ "\"\"", "\\\\", "//", "b\b", "f\f", "n\n", "r\r", "t\t", NULL
+};
+
+static char
+collect_string_escape(state_t *s)
+{
+ int i;
+ char c = popchar(s);
+
+ if (c == '\0') {
+ posterror(s, EPROTO, "EOF mid-escape sequence");
+ return (-1);
+ }
+
+ /*
+ * Handle four-digit Unicode escapes up to and including \u007f.
+ * Strings that cannot be represented as 7-bit clean ASCII are not
+ * currently supported.
+ */
+ if (c == 'u') {
+ int res;
+ int ndigs = 0;
+ char digs[5];
+
+ /*
+ * Deal with 4-digit unicode escape.
+ */
+ while (ndigs < 4) {
+ if ((digs[ndigs++] = popchar(s)) == '\0') {
+ posterror(s, EPROTO, "EOF mid-escape "
+ "sequence");
+ return (-1);
+ }
+ }
+ digs[4] = '\0';
+ if ((res = atoi(digs)) > 127) {
+ posterror(s, EPROTO, "unicode escape above 0x7f");
+ return (-1);
+ }
+
+ if (custr_appendc(s->s_collect, res) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * See if this is a C-style escape character we recognise.
+ */
+ for (i = 0; escape_pairs[i] != NULL; i++) {
+ char *ep = escape_pairs[i];
+ if (ep[0] == c) {
+ if (custr_appendc(s->s_collect, ep[1]) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ return (0);
+ }
+ }
+
+ posterror(s, EPROTO, "unrecognised escape sequence");
+ return (-1);
+}
+
+static int
+collect_string(state_t *s)
+{
+ custr_reset(s->s_collect);
+
+ for (;;) {
+ char c;
+
+ switch (c = popchar(s)) {
+ case '"':
+ /*
+ * Legal End of String.
+ */
+ return (0);
+
+ case '\0':
+ posterror(s, EPROTO, "EOF mid-string");
+ return (-1);
+
+ case '\\':
+ /*
+ * Escape Characters and Sequences.
+ */
+ if (collect_string_escape(s) != 0) {
+ return (-1);
+ }
+ break;
+
+ default:
+ if (custr_appendc(s->s_collect, c) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ break;
+ }
+ }
+}
+
+static int
+collect_bareword(state_t *s)
+{
+ custr_reset(s->s_collect);
+
+ for (;;) {
+ if (!islower(peekchar(s))) {
+ return (0);
+ }
+
+ if (custr_appendc(s->s_collect, popchar(s)) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ }
+}
+
+static void
+hdlr_bareword(state_t *s)
+{
+ const char *str;
+
+ if (collect_bareword(s) != 0) {
+ return;
+ }
+
+ str = custr_cstr(s->s_collect);
+ if (strcmp(str, "true") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
+ s->s_top->pf_value = (void *)B_TRUE;
+ } else if (strcmp(str, "false") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
+ s->s_top->pf_value = (void *)B_FALSE;
+ } else if (strcmp(str, "null") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_NULL;
+ } else {
+ posterror(s, EPROTO, "expected 'true', 'false' or 'null'");
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+/* ARGSUSED */
+static int
+collect_number(state_t *s, boolean_t *isint, int32_t *result,
+ double *fresult __GNU_UNUSED)
+{
+ boolean_t neg = B_FALSE;
+ int t;
+
+ custr_reset(s->s_collect);
+
+ if (peekchar(s) == '-') {
+ neg = B_TRUE;
+ (void) popchar(s);
+ }
+ /*
+ * Read the 'int' portion:
+ */
+ if (!isdigit(peekchar(s))) {
+ posterror(s, EPROTO, "malformed number: expected digit (0-9)");
+ return (-1);
+ }
+ for (;;) {
+ if (!isdigit(peekchar(s))) {
+ break;
+ }
+ if (custr_appendc(s->s_collect, popchar(s)) != 0) {
+ posterror(s, errno, "custr_append failure");
+ return (-1);
+ }
+ }
+ if (peekchar(s) == '.' || peekchar(s) == 'e' || peekchar(s) == 'E') {
+ posterror(s, ENOTSUP, "do not yet support FRACs or EXPs");
+ return (-1);
+ }
+
+ t = atoi(custr_cstr(s->s_collect));
+
+ *isint = B_TRUE;
+ *result = (neg == B_TRUE) ? (-t) : t;
+ return (0);
+}
+
+static void
+hdlr_number(state_t *s)
+{
+ boolean_t isint;
+ int32_t result;
+ double fresult;
+
+ if (collect_number(s, &isint, &result, &fresult) != 0) {
+ return;
+ }
+
+ if (isint == B_TRUE) {
+ s->s_top->pf_value = (void *)(uintptr_t)result;
+ s->s_top->pf_value_type = JSON_TYPE_INTEGER;
+ } else {
+ s->s_top->pf_value = malloc(sizeof (fresult));
+ bcopy(&fresult, s->s_top->pf_value, sizeof (fresult));
+ s->s_top->pf_value_type = JSON_TYPE_DOUBLE;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+static void
+hdlr_rest(state_t *s)
+{
+ char c;
+ discard_whitespace(s);
+ c = popchar(s);
+ switch (c) {
+ case '{':
+ movestate(s, PARSE_OBJECT);
+ return;
+
+ case '[':
+ movestate(s, PARSE_ARRAY);
+ return;
+
+ default:
+ posterror(s, EPROTO, "EOF before object or array");
+ return;
+ }
+}
+
+static int
+add_empty_child(state_t *s)
+{
+ /*
+ * Here, we create an empty nvlist to represent this object
+ * or array:
+ */
+ nvlist_t *empty;
+ if (nvlist_alloc(&empty, NV_UNIQUE_NAME, 0) != 0) {
+ posterror(s, errno, "nvlist_alloc failure");
+ return (-1);
+ }
+ if (s->s_top->pf_next != NULL) {
+ /*
+ * If we're a child of the frame above, we store ourselves in
+ * that frame's nvlist:
+ */
+ nvlist_t *nvl = s->s_top->pf_next->pf_nvl;
+ char *key = s->s_top->pf_next->pf_key;
+
+ if (nvlist_add_nvlist(nvl, key, empty) != 0) {
+ posterror(s, errno, "nvlist_add_nvlist failure");
+ nvlist_free(empty);
+ return (-1);
+ }
+ nvlist_free(empty);
+ if (nvlist_lookup_nvlist(nvl, key, &empty) != 0) {
+ posterror(s, errno, "nvlist_lookup_nvlist failure");
+ return (-1);
+ }
+ }
+ s->s_top->pf_nvl = empty;
+ return (0);
+}
+
+static int
+decorate_array(state_t *s)
+{
+ int idx = s->s_top->pf_array_index;
+ /*
+ * When we are done creating an array, we store a 'length'
+ * property on it, as well as an internal-use marker value.
+ */
+ if (nvlist_add_boolean(s->s_top->pf_nvl, JSON_MARKER_ARRAY) != 0 ||
+ nvlist_add_uint32(s->s_top->pf_nvl, "length", idx) != 0) {
+ posterror(s, errno, "nvlist_add failure");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+hdlr_array(state_t *s)
+{
+ s->s_top->pf_value_type = JSON_TYPE_ARRAY;
+
+ if (add_empty_child(s) != 0) {
+ return;
+ }
+
+ discard_whitespace(s);
+
+ switch (peekchar(s)) {
+ case ']':
+ (void) popchar(s);
+
+ if (decorate_array(s) != 0) {
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+ return;
+
+ default:
+ movestate(s, PARSE_ARRAY_VALUE);
+ return;
+ }
+}
+
+static void
+hdlr_array_comma(state_t *s)
+{
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case ']':
+ if (decorate_array(s) != 0) {
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+ return;
+ case ',':
+ movestate(s, PARSE_ARRAY_VALUE);
+ return;
+ default:
+ posterror(s, EPROTO, "expected ',' or ']'");
+ return;
+ }
+}
+
+static void
+hdlr_array_value(state_t *s)
+{
+ char c;
+
+ /*
+ * Generate keyname from the next array index:
+ */
+ if (s->s_top->pf_key != NULL) {
+ (void) fprintf(stderr, "pf_key not null! was %s\n",
+ s->s_top->pf_key);
+ abort();
+ }
+
+ if (asprintf(&s->s_top->pf_key, "%d", s->s_top->pf_array_index++) < 0) {
+ posterror(s, errno, "asprintf failure");
+ return;
+ }
+
+ discard_whitespace(s);
+
+ /*
+ * Select which type handler we need for the next value:
+ */
+ switch (c = peekchar(s)) {
+ case '"':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_STRING, PARSE_ARRAY_COMMA);
+ return;
+
+ case '{':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_OBJECT, PARSE_ARRAY_COMMA);
+ return;
+
+ case '[':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_ARRAY, PARSE_ARRAY_COMMA);
+ return;
+
+ default:
+ if (islower(c)) {
+ (void) pushstate(s, PARSE_BAREWORD,
+ PARSE_ARRAY_COMMA);
+ return;
+ } else if (c == '-' || isdigit(c)) {
+ (void) pushstate(s, PARSE_NUMBER, PARSE_ARRAY_COMMA);
+ return;
+ } else {
+ posterror(s, EPROTO, "unexpected character at start "
+ "of value");
+ return;
+ }
+ }
+}
+
+static void
+hdlr_object(state_t *s)
+{
+ s->s_top->pf_value_type = JSON_TYPE_OBJECT;
+
+ if (add_empty_child(s) != 0) {
+ return;
+ }
+
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case '}':
+ movestate(s, PARSE_DONE);
+ return;
+
+ case '"':
+ movestate(s, PARSE_KEY_STRING);
+ return;
+
+ default:
+ posterror(s, EPROTO, "expected key or '}'");
+ return;
+ }
+}
+
+static void
+hdlr_key_string(state_t *s)
+{
+ if (collect_string(s) != 0) {
+ return;
+ }
+
+ /*
+ * Record the key name of the next value.
+ */
+ if ((s->s_top->pf_key = strdup(custr_cstr(s->s_collect))) == NULL) {
+ posterror(s, errno, "strdup failure");
+ return;
+ }
+
+ movestate(s, PARSE_COLON);
+}
+
+static void
+hdlr_colon(state_t *s)
+{
+ char c;
+ discard_whitespace(s);
+
+ if ((c = popchar(s)) != ':') {
+ posterror(s, EPROTO, "expected ':'");
+ return;
+ }
+
+ discard_whitespace(s);
+
+ /*
+ * Select which type handler we need for the value after the colon:
+ */
+ switch (c = peekchar(s)) {
+ case '"':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_STRING, PARSE_OBJECT_COMMA);
+ return;
+
+ case '{':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_OBJECT, PARSE_OBJECT_COMMA);
+ return;
+
+ case '[':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_ARRAY, PARSE_OBJECT_COMMA);
+ return;
+
+ default:
+ if (islower(c)) {
+ (void) pushstate(s, PARSE_BAREWORD, PARSE_OBJECT_COMMA);
+ return;
+ } else if (c == '-' || isdigit(c)) {
+ (void) pushstate(s, PARSE_NUMBER, PARSE_OBJECT_COMMA);
+ return;
+ } else {
+ (void) posterror(s, EPROTO, "unexpected character at "
+ "start of value");
+ return;
+ }
+ }
+}
+
+static void
+hdlr_object_comma(state_t *s)
+{
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case '}':
+ movestate(s, PARSE_DONE);
+ return;
+
+ case ',':
+ discard_whitespace(s);
+ if (popchar(s) != '"') {
+ posterror(s, EPROTO, "expected '\"'");
+ return;
+ }
+ movestate(s, PARSE_KEY_STRING);
+ return;
+
+ default:
+ posterror(s, EPROTO, "expected ',' or '}'");
+ return;
+ }
+}
+
+static void
+hdlr_string(state_t *s)
+{
+ if (collect_string(s) != 0) {
+ return;
+ }
+
+ s->s_top->pf_value_type = JSON_TYPE_STRING;
+ if ((s->s_top->pf_value = strdup(custr_cstr(s->s_collect))) == NULL) {
+ posterror(s, errno, "strdup failure");
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+static int
+store_value(state_t *s)
+{
+ nvlist_t *targ = s->s_top->pf_next->pf_nvl;
+ char *key = s->s_top->pf_next->pf_key;
+ json_type_t type = s->s_top->pf_value_type;
+ int ret = 0;
+
+ switch (type) {
+ case JSON_TYPE_STRING:
+ if (nvlist_add_string(targ, key, s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_string failure");
+ ret = -1;
+ }
+ free(s->s_top->pf_value);
+ break;
+
+ case JSON_TYPE_BOOLEAN:
+ if (nvlist_add_boolean_value(targ, key,
+ (boolean_t)s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_boolean_value "
+ "failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_NULL:
+ if (nvlist_add_boolean(targ, key) != 0) {
+ posterror(s, errno, "nvlist_add_boolean failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_INTEGER:
+ if (nvlist_add_int32(targ, key,
+ (int32_t)(uintptr_t)s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_int32 failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_ARRAY:
+ case JSON_TYPE_OBJECT:
+ /*
+ * Objects and arrays are already 'stored' in their target
+ * nvlist on creation. See: hdlr_object, hdlr_array.
+ */
+ break;
+
+ default:
+ (void) fprintf(stderr, "ERROR: could not store unknown "
+ "type %d\n", type);
+ abort();
+ }
+
+ s->s_top->pf_value = NULL;
+ free(s->s_top->pf_next->pf_key);
+ s->s_top->pf_next->pf_key = NULL;
+ return (ret);
+}
+
+static parse_frame_t *
+parse_frame_free(parse_frame_t *pf, boolean_t free_nvl)
+{
+ parse_frame_t *next = pf->pf_next;
+ if (pf->pf_key != NULL) {
+ free(pf->pf_key);
+ }
+ if (pf->pf_value != NULL) {
+ abort();
+ }
+ if (free_nvl && pf->pf_nvl != NULL) {
+ nvlist_free(pf->pf_nvl);
+ }
+ free(pf);
+ return (next);
+}
+
+static parse_handler_t hdlrs[] = {
+ NULL, /* PARSE_DONE */
+ hdlr_rest, /* PARSE_REST */
+ hdlr_object, /* PARSE_OBJECT */
+ hdlr_key_string, /* PARSE_KEY_STRING */
+ hdlr_colon, /* PARSE_COLON */
+ hdlr_string, /* PARSE_STRING */
+ hdlr_object_comma, /* PARSE_OBJECT_COMMA */
+ hdlr_array, /* PARSE_ARRAY */
+ hdlr_bareword, /* PARSE_BAREWORD */
+ hdlr_number, /* PARSE_NUMBER */
+ hdlr_array_value, /* PARSE_ARRAY_VALUE */
+ hdlr_array_comma /* PARSE_ARRAY_COMMA */
+};
+#define NUM_PARSE_HANDLERS (int)(sizeof (hdlrs) / sizeof (hdlrs[0]))
+
+int
+nvlist_parse_json(const char *buf, size_t buflen, nvlist_t **nvlp,
+ nvlist_parse_json_flags_t flag, nvlist_parse_json_error_t *errout)
+{
+ state_t s;
+
+ /*
+ * Check for valid flags:
+ */
+ if ((flag & NVJSON_FORCE_INTEGER) && (flag & NVJSON_FORCE_DOUBLE)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((flag & ~NVJSON_ALL) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Initialise parsing state structure:
+ */
+ bzero(&s, sizeof (s));
+ s.s_in = buf;
+ s.s_pos = 0;
+ s.s_len = buflen;
+ s.s_flags = flag;
+
+ /*
+ * Allocate the collect buffer string.
+ */
+ if (custr_alloc(&s.s_collect) != 0) {
+ s.s_errno = errno;
+ if (errout != NULL) {
+ (void) snprintf(errout->nje_message,
+ sizeof (errout->nje_message),
+ "custr alloc failure: %s",
+ strerror(errno));
+ }
+ goto out;
+ }
+
+ /*
+ * If the caller has requested error information, allocate the error
+ * string now.
+ */
+ if (errout != NULL) {
+ if (custr_alloc_buf(&s.s_errstr, errout->nje_message,
+ sizeof (errout->nje_message)) != 0) {
+ s.s_errno = errno;
+ (void) snprintf(errout->nje_message,
+ sizeof (errout->nje_message),
+ "custr alloc failure: %s",
+ strerror(errno));
+ goto out;
+ }
+ custr_reset(s.s_errstr);
+ }
+
+ /*
+ * Allocate top-most stack frame:
+ */
+ if ((s.s_top = calloc(1, sizeof (*s.s_top))) == NULL) {
+ s.s_errno = errno;
+ goto out;
+ }
+
+ s.s_top->pf_ps = PARSE_REST;
+ for (;;) {
+ if (s.s_top->pf_ps < 0) {
+ /*
+ * The parser reported an error.
+ */
+ goto out;
+ }
+
+ if (s.s_top->pf_ps == PARSE_DONE) {
+ if (s.s_top->pf_next == NULL) {
+ /*
+ * Last frame, so we're really
+ * done.
+ */
+ *nvlp = s.s_top->pf_nvl;
+ goto out;
+ } else {
+ /*
+ * Otherwise, pop a frame and continue in
+ * previous state. Copy out the value we
+ * created in the old frame:
+ */
+ if (store_value(&s) != 0) {
+ goto out;
+ }
+
+ /*
+ * Free old frame:
+ */
+ s.s_top = parse_frame_free(s.s_top, B_FALSE);
+ }
+ }
+
+ /*
+ * Dispatch to parser handler routine for this state:
+ */
+ if (s.s_top->pf_ps >= NUM_PARSE_HANDLERS ||
+ hdlrs[s.s_top->pf_ps] == NULL) {
+ (void) fprintf(stderr, "no handler for state %d\n",
+ s.s_top->pf_ps);
+ abort();
+ }
+ hdlrs[s.s_top->pf_ps](&s);
+ }
+
+out:
+ if (errout != NULL) {
+ /*
+ * Copy out error number and parse position. The custr_t for
+ * the error message was backed by the buffer in the error
+ * object, so no copying is required.
+ */
+ errout->nje_errno = s.s_errno;
+ errout->nje_pos = s.s_pos;
+ }
+
+ /*
+ * Free resources:
+ */
+ while (s.s_top != NULL) {
+ s.s_top = parse_frame_free(s.s_top, s.s_errno == 0 ? B_FALSE :
+ B_TRUE);
+ }
+ custr_free(s.s_collect);
+ custr_free(s.s_errstr);
+
+ errno = s.s_errno;
+ return (s.s_errno == 0 ? 0 : -1);
+}
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files_json.h b/usr/src/lib/varpd/files/common/libvarpd_files_json.h
new file mode 100644
index 0000000000..27506e22d6
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files_json.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_FILES_JSON_H
+#define _LIBVARPD_FILES_JSON_H
+
+#include <libnvpair.h>
+#include <libcmdutils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum nvlist_parse_json_flags {
+ NVJSON_FORCE_INTEGER = 0x01,
+ NVJSON_FORCE_DOUBLE = 0x02,
+ NVJSON_ERRORS_TO_STDERR = 0x04,
+ NVJSON_DEBUG = 0x08
+} nvlist_parse_json_flags_t;
+
+typedef struct nvlist_parse_json_error {
+ int nje_errno;
+ long nje_pos;
+ char nje_message[512];
+} nvlist_parse_json_error_t;
+
+#define NVJSON_ALL \
+ (NVJSON_FORCE_INTEGER | \
+ NVJSON_FORCE_DOUBLE | \
+ NVJSON_ERRORS_TO_STDERR | \
+ NVJSON_DEBUG)
+
+extern int nvlist_parse_json(const char *, size_t, nvlist_t **,
+ nvlist_parse_json_flags_t, nvlist_parse_json_error_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_FILES_JSON_H */
diff --git a/usr/src/lib/varpd/files/common/llib-lvarpd_files b/usr/src/lib/varpd/files/common/llib-lvarpd_files
new file mode 100644
index 0000000000..03c34f4fcb
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/llib-lvarpd_files
@@ -0,0 +1,18 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
diff --git a/usr/src/lib/varpd/files/common/mapfile-vers b/usr/src/lib/varpd/files/common/mapfile-vers
new file mode 100644
index 0000000000..6b7c5a5067
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/mapfile-vers
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/files/i386/Makefile b/usr/src/lib/varpd/files/i386/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/files/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/files/sparc/Makefile b/usr/src/lib/varpd/files/sparc/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/files/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/files/sparcv9/Makefile b/usr/src/lib/varpd/files/sparcv9/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/files/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/libvarpd/Makefile b/usr/src/lib/varpd/libvarpd/Makefile
new file mode 100644
index 0000000000..2a4f8f070c
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/Makefile
@@ -0,0 +1,55 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+HDRS = libvarpd.h libvarpd_client.h libvarpd_provider.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+TYPECHECK_LIB = libvarpd.so.1
+TYPELIST = \
+ varpd_client_instance_arg_t \
+ varpd_client_nprops_arg_t \
+ varpd_client_propinfo_arg_t \
+ varpd_client_eresp_t \
+ varpd_persist_header_t \
+ overlay_targ_cache_entry_t \
+ overlay_targ_cache_t \
+ overlay_targ_cache_iter_t
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS) $(VARPD_MAPFILES) install_h
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS) $(TYPECHECK)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/libvarpd/Makefile.com b/usr/src/lib/varpd/libvarpd/Makefile.com
new file mode 100644
index 0000000000..1521f83f8f
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/Makefile.com
@@ -0,0 +1,53 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd.a
+VERS = .1
+OBJECTS = libvarpd.o \
+ libvarpd_arp.o \
+ libvarpd_client.o \
+ libvarpd_door.o \
+ libvarpd_overlay.o \
+ libvarpd_panic.o \
+ libvarpd_persist.o \
+ libvarpd_prop.o \
+ libvarpd_plugin.o \
+ libvarpd_util.o
+
+include ../../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc -lavl -lumem -lidspace -lnvpair -lmd5 -lrename \
+ -lbunyan
+CPPFLAGS += -I../common
+
+CERRWARN += -erroff=E_STRUCT_DERIVED_FROM_FLEX_MBR
+LINTFLAGS += -erroff=E_STRUCT_DERIVED_FROM_FLEX_MBR \
+ -erroff=E_BAD_PTR_CAST_ALIGN
+LINTFLAGS64 += -erroff=E_STRUCT_DERIVED_FROM_FLEX_MBR \
+ -erroff=E_BAD_PTR_CAST_ALIGN
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/libvarpd/amd64/Makefile b/usr/src/lib/varpd/libvarpd/amd64/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd.c b/usr/src/lib/varpd/libvarpd/common/libvarpd.c
new file mode 100644
index 0000000000..e4460089cc
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd.c
@@ -0,0 +1,360 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd library
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <umem.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/avl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <libvarpd_impl.h>
+
+static int
+libvarpd_instance_comparator(const void *lp, const void *rp)
+{
+ const varpd_instance_t *lpp, *rpp;
+ lpp = lp;
+ rpp = rp;
+
+ if (lpp->vri_id > rpp->vri_id)
+ return (1);
+ if (lpp->vri_id < rpp->vri_id)
+ return (-1);
+ return (0);
+}
+
+static int
+libvarpd_instance_lcomparator(const void *lp, const void *rp)
+{
+ const varpd_instance_t *lpp, *rpp;
+ lpp = lp;
+ rpp = rp;
+
+ if (lpp->vri_linkid > rpp->vri_linkid)
+ return (1);
+ if (lpp->vri_linkid < rpp->vri_linkid)
+ return (-1);
+ return (0);
+}
+
+int
+libvarpd_create(varpd_handle_t **vphp)
+{
+ int ret;
+ varpd_impl_t *vip;
+ char buf[32];
+
+ if (vphp == NULL)
+ return (EINVAL);
+
+ *vphp = NULL;
+ vip = umem_alloc(sizeof (varpd_impl_t), UMEM_DEFAULT);
+ if (vip == NULL)
+ return (errno);
+
+ bzero(vip, sizeof (varpd_impl_t));
+ (void) snprintf(buf, sizeof (buf), "varpd_%p", vip);
+ vip->vdi_idspace = id_space_create(buf, LIBVARPD_ID_MIN,
+ LIBVARPD_ID_MAX);
+ if (vip->vdi_idspace == NULL) {
+ int ret = errno;
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ vip->vdi_qcache = umem_cache_create("query", sizeof (varpd_query_t), 0,
+ NULL, NULL, NULL, NULL, NULL, 0);
+ if (vip->vdi_qcache == NULL) {
+ int ret = errno;
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ if ((ret = libvarpd_overlay_init(vip)) != 0) {
+ umem_cache_destroy(vip->vdi_qcache);
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ if ((ret = bunyan_init("varpd", &vip->vdi_bunyan)) != 0) {
+ libvarpd_overlay_fini(vip);
+ umem_cache_destroy(vip->vdi_qcache);
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ libvarpd_persist_init(vip);
+
+ avl_create(&vip->vdi_plugins, libvarpd_plugin_comparator,
+ sizeof (varpd_plugin_t), offsetof(varpd_plugin_t, vpp_node));
+
+ avl_create(&vip->vdi_instances, libvarpd_instance_comparator,
+ sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_inode));
+ avl_create(&vip->vdi_linstances, libvarpd_instance_lcomparator,
+ sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_lnode));
+
+ if (mutex_init(&vip->vdi_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create mutex: %d", errno);
+
+ vip->vdi_doorfd = -1;
+ *vphp = (varpd_handle_t *)vip;
+ return (0);
+}
+
+void
+libvarpd_destroy(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ libvarpd_overlay_lookup_quiesce(vhp);
+ if (mutex_destroy(&vip->vdi_lock) != 0)
+ libvarpd_panic("failed to destroy mutex: %d", errno);
+ libvarpd_persist_fini(vip);
+ libvarpd_overlay_fini(vip);
+ umem_cache_destroy(vip->vdi_qcache);
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+}
+
+int
+libvarpd_instance_create(varpd_handle_t *vhp, datalink_id_t linkid,
+ const char *pname, varpd_instance_handle_t **outp)
+{
+ int ret;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+ varpd_plugin_t *plugin;
+ varpd_instance_t *inst, lookup;
+ overlay_plugin_dest_t dest;
+ uint64_t vid;
+
+ /*
+ * We should really have our own errnos.
+ */
+ plugin = libvarpd_plugin_lookup(vip, pname);
+ if (plugin == NULL)
+ return (ENOENT);
+
+ if ((ret = libvarpd_overlay_info(vip, linkid, &dest, NULL, &vid)) != 0)
+ return (ret);
+
+ inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
+ if (inst == NULL)
+ return (ENOMEM);
+
+ inst->vri_id = id_alloc(vip->vdi_idspace);
+ if (inst->vri_id == -1)
+ libvarpd_panic("failed to allocate id from vdi_idspace: %d",
+ errno);
+ inst->vri_linkid = linkid;
+ inst->vri_vnetid = vid;
+ inst->vri_mode = plugin->vpp_mode;
+ inst->vri_dest = dest;
+ inst->vri_plugin = plugin;
+ inst->vri_impl = vip;
+ inst->vri_flags = 0;
+ if ((ret = plugin->vpp_ops->vpo_create((varpd_provider_handle_t *)inst,
+ &inst->vri_private, dest)) != 0) {
+ id_free(vip->vdi_idspace, inst->vri_id);
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (ret);
+ }
+
+ if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create mutex: %d", errno);
+
+ mutex_enter(&vip->vdi_lock);
+ lookup.vri_id = inst->vri_id;
+ if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate instance with id %d",
+ lookup.vri_id);
+ avl_add(&vip->vdi_instances, inst);
+ lookup.vri_linkid = inst->vri_linkid;
+ if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate linstance with id %d",
+ lookup.vri_linkid);
+ avl_add(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+ *outp = (varpd_instance_handle_t *)inst;
+ return (0);
+}
+
+uint64_t
+libvarpd_instance_id(varpd_instance_handle_t *ihp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+ return (inst->vri_id);
+}
+
+uint64_t
+libvarpd_plugin_vnetid(varpd_provider_handle_t *vhp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)vhp;
+ return (inst->vri_vnetid);
+}
+
+varpd_instance_handle_t *
+libvarpd_instance_lookup(varpd_handle_t *vhp, uint64_t id)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+ varpd_instance_t lookup, *retp;
+
+ lookup.vri_id = id;
+ mutex_enter(&vip->vdi_lock);
+ retp = avl_find(&vip->vdi_instances, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+ return ((varpd_instance_handle_t *)retp);
+}
+
+/*
+ * If this function becomes external to varpd, we need to change it to return a
+ * varpd_instance_handle_t.
+ */
+varpd_instance_t *
+libvarpd_instance_lookup_by_dlid(varpd_impl_t *vip, datalink_id_t linkid)
+{
+ varpd_instance_t lookup, *retp;
+
+ lookup.vri_linkid = linkid;
+ mutex_enter(&vip->vdi_lock);
+ retp = avl_find(&vip->vdi_linstances, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+ return (retp);
+}
+
+/*
+ * When an instance is being destroyed, that means we should deactivate it, as
+ * well as clean it up. That means here, the proper order is calling the plug-in
+ * stop and then the destroy function.
+ */
+void
+libvarpd_instance_destroy(varpd_instance_handle_t *ihp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ /*
+ * First things first, remove it from global visibility.
+ */
+ mutex_enter(&vip->vdi_lock);
+ avl_remove(&vip->vdi_instances, inst);
+ avl_remove(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+
+ mutex_enter(&inst->vri_lock);
+
+ /*
+ * We need to clean up this instance, that means remove it from
+ * persistence and stopping it. Then finally we'll have to clean it up
+ * entirely.
+ */
+ if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
+ inst->vri_flags &= ~VARPD_INSTANCE_F_ACTIVATED;
+ libvarpd_torch_instance(vip, inst);
+ inst->vri_plugin->vpp_ops->vpo_stop(inst->vri_private);
+ inst->vri_plugin->vpp_ops->vpo_destroy(inst->vri_private);
+ inst->vri_private = NULL;
+ }
+ mutex_exit(&inst->vri_lock);
+
+ /* Do the full clean up of the instance */
+ if (mutex_destroy(&inst->vri_lock) != 0)
+ libvarpd_panic("failed to destroy instance vri_lock");
+ id_free(vip->vdi_idspace, inst->vri_id);
+ umem_free(inst, sizeof (varpd_instance_t));
+}
+
+int
+libvarpd_instance_activate(varpd_instance_handle_t *ihp)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+
+ mutex_enter(&inst->vri_lock);
+
+ if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
+ ret = EEXIST;
+ goto out;
+ }
+
+ if ((ret = inst->vri_plugin->vpp_ops->vpo_start(inst->vri_private)) !=
+ 0)
+ goto out;
+
+ if ((ret = libvarpd_persist_instance(inst->vri_impl, inst)) != 0)
+ goto out;
+
+ /*
+ * If this fails, we don't need to call stop, as the caller should end
+ * up calling destroy on the instance, which takes care of calling stop
+ * and destroy.
+ */
+ if ((ret = libvarpd_overlay_associate(inst)) != 0)
+ goto out;
+
+ inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
+
+out:
+ mutex_exit(&inst->vri_lock);
+ return (ret);
+}
+
+const bunyan_logger_t *
+libvarpd_plugin_bunyan(varpd_provider_handle_t *vhp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)vhp;
+ return (inst->vri_impl->vdi_bunyan);
+}
+
+static void
+libvarpd_prefork(void)
+{
+ libvarpd_plugin_prefork();
+}
+
+static void
+libvarpd_postfork(void)
+{
+ libvarpd_plugin_postfork();
+}
+
+#pragma init(libvarpd_init)
+static void
+libvarpd_init(void)
+{
+ libvarpd_plugin_init();
+ if (pthread_atfork(libvarpd_prefork, libvarpd_postfork,
+ libvarpd_postfork) != 0)
+ libvarpd_panic("failed to create varpd atfork: %d", errno);
+}
+
+#pragma fini(libvarpd_fini)
+static void
+libvarpd_fini(void)
+{
+ libvarpd_plugin_fini();
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd.h b/usr/src/lib/varpd/libvarpd/common/libvarpd.h
new file mode 100644
index 0000000000..aaf78e2ca6
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd.h
@@ -0,0 +1,77 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_H
+#define _LIBVARPD_H
+
+/*
+ * varpd interfaces
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/mac.h>
+#include <libvarpd_client.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __varpd_handle varpd_handle_t;
+typedef struct __varpd_prop_handle varpd_prop_handle_t;
+typedef struct __varpd_instance_handle varpd_instance_handle_t;
+
+extern int libvarpd_create(varpd_handle_t **);
+extern void libvarpd_destroy(varpd_handle_t *);
+
+extern int libvarpd_persist_enable(varpd_handle_t *, const char *);
+extern int libvarpd_persist_restore(varpd_handle_t *);
+extern int libvarpd_persist_disable(varpd_handle_t *);
+
+extern int libvarpd_instance_create(varpd_handle_t *, datalink_id_t,
+ const char *, varpd_instance_handle_t **);
+extern uint64_t libvarpd_instance_id(varpd_instance_handle_t *);
+extern varpd_instance_handle_t *libvarpd_instance_lookup(varpd_handle_t *,
+ uint64_t);
+extern void libvarpd_instance_destroy(varpd_instance_handle_t *);
+extern int libvarpd_instance_activate(varpd_instance_handle_t *);
+
+extern int libvarpd_plugin_load(varpd_handle_t *, const char *);
+typedef int (*libvarpd_plugin_walk_f)(varpd_handle_t *, const char *, void *);
+extern int libvarpd_plugin_walk(varpd_handle_t *, libvarpd_plugin_walk_f,
+ void *);
+
+extern int libvarpd_prop_handle_alloc(varpd_handle_t *,
+ varpd_instance_handle_t *, varpd_prop_handle_t **);
+extern void libvarpd_prop_handle_free(varpd_prop_handle_t *);
+extern int libvarpd_prop_nprops(varpd_instance_handle_t *, uint_t *);
+extern int libvarpd_prop_info_fill(varpd_prop_handle_t *, uint_t);
+extern int libvarpd_prop_info(varpd_prop_handle_t *, const char **, uint_t *,
+ uint_t *, const void **, uint32_t *, const mac_propval_range_t **);
+extern int libvarpd_prop_get(varpd_prop_handle_t *, void *, uint32_t *);
+extern int libvarpd_prop_set(varpd_prop_handle_t *, const void *, uint32_t);
+
+extern int libvarpd_door_server_create(varpd_handle_t *, const char *);
+extern void libvarpd_door_server_destroy(varpd_handle_t *);
+
+extern void libvarpd_overlay_lookup_run(varpd_handle_t *);
+extern void libvarpd_overlay_lookup_quiesce(varpd_handle_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c
new file mode 100644
index 0000000000..df69207fe0
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c
@@ -0,0 +1,650 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Common routines for implmeenting proxy arp
+ */
+
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/udp.h>
+#include <netinet/dhcp.h>
+#include <libvarpd_impl.h>
+#include <sys/vlan.h>
+#include <strings.h>
+#include <assert.h>
+
+#define IPV6_VERSION 6
+
+typedef struct varpd_arp_query {
+ int vaq_type;
+ char vaq_buf[ETHERMAX + VLAN_TAGSZ];
+ size_t vaq_bsize;
+ uint8_t vaq_lookup[ETHERADDRL];
+ struct sockaddr_storage vaq_sock;
+ varpd_instance_t *vaq_inst;
+ struct ether_arp *vaq_ea;
+ varpd_query_handle_t *vaq_query;
+ const overlay_targ_lookup_t *vaq_otl;
+ ip6_t *vaq_ip6;
+ nd_neighbor_solicit_t *vaq_ns;
+} varpd_arp_query_t;
+
+typedef struct varpd_dhcp_query {
+ char vdq_buf[ETHERMAX + VLAN_TAGSZ];
+ size_t vdq_bsize;
+ uint8_t vdq_lookup[ETHERADDRL];
+ const overlay_targ_lookup_t *vdq_otl;
+ varpd_instance_t *vdq_inst;
+ varpd_query_handle_t *vdq_query;
+ struct ether_header *vdq_ether;
+} varpd_dhcp_query_t;
+
+static const uint8_t libvarpd_arp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+
+void
+libvarpd_plugin_proxy_arp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ varpd_arp_query_t *vaq;
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+ struct ether_arp *ea;
+ struct sockaddr_in *ip;
+
+ vaq = umem_alloc(sizeof (varpd_arp_query_t), UMEM_DEFAULT);
+ if (vaq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vaq->vaq_bsize = sizeof (vaq->vaq_buf);
+
+ if (otl->otl_sap != ETHERTYPE_ARP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * An ARP packet should not be very large because it's definited to only
+ * be allowed to have a single entry at a given time. But our data must
+ * be at least as large as an ether_arp and our header must be at least
+ * as large as a standard ethernet header.
+ */
+ if (otl->otl_hdrsize + otl->otl_pktsize > vaq->vaq_bsize ||
+ otl->otl_pktsize < sizeof (struct ether_arp) ||
+ otl->otl_hdrsize < sizeof (struct ether_header)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vaq->vaq_buf,
+ &vaq->vaq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + otl->otl_pktsize < vaq->vaq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ ea = (void *)((uintptr_t)vaq->vaq_buf + (uintptr_t)otl->otl_hdrsize);
+
+ /*
+ * Make sure it matches something that we know about.
+ */
+ if (ntohs(ea->ea_hdr.ar_hrd) != ARPHRD_ETHER ||
+ ntohs(ea->ea_hdr.ar_pro) != ETHERTYPE_IP ||
+ ea->ea_hdr.ar_hln != ETHERADDRL ||
+ ea->ea_hdr.ar_pln != sizeof (ea->arp_spa) ||
+ ntohs(ea->ea_hdr.ar_op) != ARPOP_REQUEST) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * Now that we've verified that our data is sane, see if we're doing a
+ * gratuitous arp and if so, drop it. Otherwise, we may end up
+ * triggering duplicate address detection.
+ */
+ if (bcmp(ea->arp_spa, ea->arp_tpa, sizeof (ea->arp_spa)) == 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bzero(&vaq->vaq_sock, sizeof (struct sockaddr_storage));
+ ip = (struct sockaddr_in *)&vaq->vaq_sock;
+ ip->sin_family = AF_INET;
+ bcopy(ea->arp_tpa, &ip->sin_addr, sizeof (ea->arp_tpa));
+
+ vaq->vaq_type = AF_INET;
+ vaq->vaq_inst = inst;
+ vaq->vaq_ea = ea;
+ vaq->vaq_query = vqh;
+ vaq->vaq_otl = otl;
+
+ if (inst->vri_plugin->vpp_ops->vpo_arp == NULL)
+ libvarpd_panic("%s plugin asked to do arp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ inst->vri_plugin->vpp_ops->vpo_arp(inst->vri_private,
+ (varpd_arp_handle_t *)vaq, VARPD_QTYPE_ETHERNET,
+ (struct sockaddr *)ip, vaq->vaq_lookup);
+}
+
+static void
+libvarpd_proxy_arp_fini(varpd_arp_query_t *vaq)
+{
+ struct ether_header *ether;
+ struct sockaddr_in *ip;
+
+ ip = (struct sockaddr_in *)&vaq->vaq_sock;
+ /*
+ * Modify our packet in place for a reply. We need to swap around the
+ * sender and target addresses.
+ */
+ vaq->vaq_ea->ea_hdr.ar_op = htons(ARPOP_REPLY);
+ bcopy(vaq->vaq_ea->arp_sha, vaq->vaq_ea->arp_tha, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, vaq->vaq_ea->arp_sha, ETHERADDRL);
+ bcopy(vaq->vaq_ea->arp_spa, &ip->sin_addr,
+ sizeof (vaq->vaq_ea->arp_spa));
+ bcopy(vaq->vaq_ea->arp_tpa, vaq->vaq_ea->arp_spa,
+ sizeof (vaq->vaq_ea->arp_spa));
+ bcopy(&ip->sin_addr, vaq->vaq_ea->arp_tpa,
+ sizeof (vaq->vaq_ea->arp_spa));
+
+ /*
+ * Finally go ahead and fix up the mac header and reply to the sender
+ * explicitly.
+ */
+ ether = (struct ether_header *)vaq->vaq_buf;
+ bcopy(&ether->ether_shost, &ether->ether_dhost, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, &ether->ether_shost, ETHERADDRL);
+
+ (void) libvarpd_overlay_inject(vaq->vaq_inst->vri_impl, vaq->vaq_otl,
+ vaq->vaq_buf, vaq->vaq_bsize);
+
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+}
+
+static uint16_t
+libvarpd_icmpv6_checksum(const ip6_t *v6hdr, const uint16_t *buf, uint16_t mlen)
+{
+ int i;
+ uint16_t *v;
+ uint32_t sum = 0;
+
+ assert(mlen % 2 == 0);
+ v = (uint16_t *)&v6hdr->ip6_src;
+ for (i = 0; i < sizeof (struct in6_addr); i += 2, v++)
+ sum += *v;
+ v = (uint16_t *)&v6hdr->ip6_dst;
+ for (i = 0; i < sizeof (struct in6_addr); i += 2, v++)
+ sum += *v;
+ sum += htons(mlen);
+#ifdef _BIG_ENDIAN
+ sum += IPPROTO_ICMPV6;
+#else
+ sum += IPPROTO_ICMPV6 << 8;
+#endif /* _BIG_ENDIAN */
+
+ for (i = 0; i < mlen; i += 2, buf++)
+ sum += *buf;
+
+ while ((sum >> 16) != 0)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return (sum & 0xffff);
+}
+
+/*
+ * Proxying NDP is much more involved than proxying ARP. For starters, NDP
+ * neighbor solicitations are implemented in terms of IPv6 ICMP as opposed to
+ * its own Ethertype. Therefore, we're going to have to grab a packet if it's a
+ * multicast packet and then determine if we actually want to do anything with
+ * it.
+ */
+void
+libvarpd_plugin_proxy_ndp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ size_t bsize, plen;
+ varpd_arp_query_t *vaq;
+ ip6_t *v6hdr;
+ nd_neighbor_solicit_t *ns;
+ nd_opt_hdr_t *opt;
+ struct sockaddr_in6 *s6;
+
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+ uint8_t *eth = NULL;
+
+ vaq = umem_alloc(sizeof (varpd_arp_query_t), UMEM_DEFAULT);
+ if (vaq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vaq->vaq_bsize = sizeof (vaq->vaq_buf);
+
+ if (otl->otl_dstaddr[0] != 0x33 ||
+ otl->otl_dstaddr[1] != 0x33) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * If we have more than a standard frame size for the ICMP neighbor
+ * solicitation, drop it. Similarly if there isn't enough data present
+ * for us, drop it.
+ */
+ if (otl->otl_hdrsize + otl->otl_pktsize > vaq->vaq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (otl->otl_pktsize < sizeof (ip6_t) +
+ sizeof (nd_neighbor_solicit_t)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vaq->vaq_buf,
+ &vaq->vaq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bsize = vaq->vaq_bsize;
+ bsize -= otl->otl_hdrsize;
+ assert(bsize > sizeof (ip6_t));
+
+ v6hdr = (ip6_t *)(vaq->vaq_buf + otl->otl_hdrsize);
+ if (((v6hdr->ip6_vfc & 0xf0) >> 4) != IPV6_VERSION) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (v6hdr->ip6_nxt != IPPROTO_ICMPV6) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * In addition to getting these requests on the multicast address for
+ * node solicitation, we may also end up getting them on a generic
+ * multicast address due to timeouts or other choices by various OSes.
+ * We should fairly liberal and accept both, even though the standard
+ * wants them to a solicitation address.
+ */
+ if (!IN6_IS_ADDR_MC_SOLICITEDNODE(&v6hdr->ip6_dst) &&
+ !IN6_IS_ADDR_MC_LINKLOCAL(&v6hdr->ip6_dst)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bsize -= sizeof (ip6_t);
+ plen = ntohs(v6hdr->ip6_plen);
+ if (bsize < plen) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * Now we know that this is an ICMPv6 request targetting the right
+ * IPv6 multicast prefix. Let's go through and verify that ICMPv6
+ * indicates that we have the real thing and ensure that per RFC 4861
+ * the target address is not a multicast address. Further, because this
+ * is a multicast on Ethernet, we must have a source link-layer address.
+ *
+ * We should probably enforce that we have a valid ICMP checksum at some
+ * point.
+ */
+ ns = (nd_neighbor_solicit_t *)(vaq->vaq_buf + otl->otl_hdrsize +
+ sizeof (ip6_t));
+ if (ns->nd_ns_type != ND_NEIGHBOR_SOLICIT && ns->nd_ns_code != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST(&ns->nd_ns_target) ||
+ IN6_IS_ADDR_V4MAPPED(&ns->nd_ns_target) ||
+ IN6_IS_ADDR_LOOPBACK(&ns->nd_ns_target)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ plen -= sizeof (nd_neighbor_solicit_t);
+ opt = (nd_opt_hdr_t *)(ns+1);
+ while (plen >= sizeof (struct nd_opt_hdr)) {
+ /* If we have an option with no lenght, that's clear bogus */
+ if (opt->nd_opt_len == 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR) {
+ eth = (uint8_t *)((uintptr_t)opt +
+ sizeof (nd_opt_hdr_t));
+ }
+ plen -= opt->nd_opt_len * 8;
+ opt = (nd_opt_hdr_t *)((uintptr_t)opt +
+ opt->nd_opt_len * 8);
+ }
+
+ if (eth == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bzero(&vaq->vaq_sock, sizeof (struct sockaddr_storage));
+ s6 = (struct sockaddr_in6 *)&vaq->vaq_sock;
+ s6->sin6_family = AF_INET6;
+ bcopy(&ns->nd_ns_target, &s6->sin6_addr, sizeof (s6->sin6_addr));
+
+ if (inst->vri_plugin->vpp_ops->vpo_arp == NULL)
+ libvarpd_panic("%s plugin asked to do arp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ vaq->vaq_type = AF_INET6;
+ vaq->vaq_inst = inst;
+ vaq->vaq_ea = NULL;
+ vaq->vaq_query = vqh;
+ vaq->vaq_otl = otl;
+ vaq->vaq_ns = ns;
+ vaq->vaq_ip6 = v6hdr;
+ inst->vri_plugin->vpp_ops->vpo_arp(inst->vri_private,
+ (varpd_arp_handle_t *)vaq, VARPD_QTYPE_ETHERNET,
+ (struct sockaddr *)s6, vaq->vaq_lookup);
+}
+
+static void
+libvarpd_proxy_ndp_fini(varpd_arp_query_t *vaq)
+{
+ char resp[ETHERMAX + VLAN_TAGSZ];
+ struct ether_header *ether;
+ nd_neighbor_advert_t *na;
+ nd_opt_hdr_t *opt;
+ ip6_t *v6hdr;
+ size_t roff = 0;
+
+ /*
+ * Now we need to assemble an RA as a response. Unlike with arp, we opt
+ * to use a new packet just to make things a bit simpler saner here.
+ */
+ v6hdr = vaq->vaq_ip6;
+ bcopy(vaq->vaq_buf, resp, vaq->vaq_otl->otl_hdrsize);
+ ether = (struct ether_header *)resp;
+ bcopy(&ether->ether_shost, &ether->ether_dhost, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, &ether->ether_shost, ETHERADDRL);
+ roff += vaq->vaq_otl->otl_hdrsize;
+ bcopy(v6hdr, resp + roff, sizeof (ip6_t));
+ v6hdr = (ip6_t *)(resp + roff);
+ bcopy(&v6hdr->ip6_src, &v6hdr->ip6_dst, sizeof (struct in6_addr));
+ bcopy(&vaq->vaq_ns->nd_ns_target, &v6hdr->ip6_src,
+ sizeof (struct in6_addr));
+ roff += sizeof (ip6_t);
+ na = (nd_neighbor_advert_t *)(resp + roff);
+ na->nd_na_type = ND_NEIGHBOR_ADVERT;
+ na->nd_na_code = 0;
+ /*
+ * RFC 4443 defines that we should set the checksum to zero before we
+ * calculate the checksumat we should set the checksum to zero before we
+ * calculate it.
+ */
+ na->nd_na_cksum = 0;
+ /*
+ * Nota bene, the header <netinet/icmp6.h> has already transformed this
+ * into the appropriate host order. Don't use htonl.
+ */
+ na->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE;
+ bcopy(&vaq->vaq_ns->nd_ns_target, &na->nd_na_target,
+ sizeof (struct in6_addr));
+ roff += sizeof (nd_neighbor_advert_t);
+
+ opt = (nd_opt_hdr_t *)(resp + roff);
+ opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+ opt->nd_opt_len = 1;
+ roff += sizeof (nd_opt_hdr_t);
+ bcopy(vaq->vaq_lookup, resp + roff, ETHERADDRL);
+ roff += ETHERADDRL;
+
+ /*
+ * Now that we've filled in the packet, go back and compute the checksum
+ * and fill in the IPv6 payload size.
+ */
+ v6hdr->ip6_plen = htons(roff - sizeof (ip6_t) -
+ vaq->vaq_otl->otl_hdrsize);
+ na->nd_na_cksum = ~libvarpd_icmpv6_checksum(v6hdr, (uint16_t *)na,
+ ntohs(v6hdr->ip6_plen)) & 0xffff;
+
+ (void) libvarpd_overlay_inject(vaq->vaq_inst->vri_impl, vaq->vaq_otl,
+ resp, roff);
+
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+}
+
+void
+libvarpd_plugin_arp_reply(varpd_arp_handle_t *vah, int action)
+{
+ varpd_arp_query_t *vaq = (varpd_arp_query_t *)vah;
+
+ if (vaq == NULL)
+ libvarpd_panic("unknown plugin passed invalid "
+ "varpd_arp_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP) {
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ } else if (action != VARPD_LOOKUP_OK)
+ libvarpd_panic("%s plugin returned invalid action %d",
+ vaq->vaq_inst->vri_plugin->vpp_name, action);
+
+ switch (vaq->vaq_type) {
+ case AF_INET:
+ libvarpd_proxy_arp_fini(vaq);
+ break;
+ case AF_INET6:
+ libvarpd_proxy_ndp_fini(vaq);
+ break;
+ default:
+ libvarpd_panic("encountered unknown vaq_type: %d",
+ vaq->vaq_type);
+ }
+}
+
+void
+libvarpd_plugin_proxy_dhcp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ varpd_dhcp_query_t *vdq;
+ struct ether_header *ether;
+ struct ip *ip;
+ struct udphdr *udp;
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+
+ vdq = umem_alloc(sizeof (varpd_dhcp_query_t), UMEM_DEFAULT);
+ if (vdq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vdq->vdq_bsize = sizeof (vdq->vdq_buf);
+
+ if (otl->otl_sap != ETHERTYPE_IP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (bcmp(otl->otl_dstaddr, libvarpd_arp_bcast, ETHERADDRL) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + otl->otl_pktsize > vdq->vdq_bsize ||
+ otl->otl_pktsize < sizeof (struct ip) + sizeof (struct udphdr) +
+ sizeof (struct dhcp) ||
+ otl->otl_hdrsize < sizeof (struct ether_header)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vdq->vdq_buf,
+ &vdq->vdq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (vdq->vdq_bsize != otl->otl_hdrsize + otl->otl_pktsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ ether = (struct ether_header *)vdq->vdq_buf;
+ ip = (struct ip *)(vdq->vdq_buf + otl->otl_hdrsize);
+
+ if (ip->ip_v != IPVERSION && ip->ip_p != IPPROTO_UDP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + ip->ip_hl * 4 + sizeof (struct udphdr) >
+ vdq->vdq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ udp = (struct udphdr *)(vdq->vdq_buf + otl->otl_hdrsize +
+ ip->ip_hl * 4);
+
+ if (ntohs(udp->uh_sport) != IPPORT_BOOTPC ||
+ ntohs(udp->uh_dport) != IPPORT_BOOTPS) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ vdq->vdq_ether = ether;
+ vdq->vdq_inst = inst;
+ vdq->vdq_query = vqh;
+ vdq->vdq_otl = otl;
+
+ if (inst->vri_plugin->vpp_ops->vpo_dhcp == NULL)
+ libvarpd_panic("%s plugin asked to do dhcp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ inst->vri_plugin->vpp_ops->vpo_dhcp(inst->vri_private,
+ (varpd_dhcp_handle_t *)vdq, VARPD_QTYPE_ETHERNET, otl,
+ vdq->vdq_lookup);
+}
+
+void
+libvarpd_plugin_dhcp_reply(varpd_dhcp_handle_t *vdh, int action)
+{
+ varpd_dhcp_query_t *vdq = (varpd_dhcp_query_t *)vdh;
+
+ if (vdq == NULL)
+ libvarpd_panic("unknown plugin passed invalid "
+ "varpd_dhcp_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP) {
+ libvarpd_plugin_query_reply(vdq->vdq_query, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ } else if (action != VARPD_LOOKUP_OK)
+ libvarpd_panic("%s plugin returned invalid action %d",
+ vdq->vdq_inst->vri_plugin->vpp_name, action);
+
+ bcopy(vdq->vdq_lookup, &vdq->vdq_ether->ether_dhost, ETHERADDRL);
+ (void) libvarpd_overlay_resend(vdq->vdq_inst->vri_impl, vdq->vdq_otl,
+ vdq->vdq_buf, vdq->vdq_bsize);
+
+ libvarpd_plugin_query_reply(vdq->vdq_query, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+}
+
+/*
+ * Inject a gratuitious ARP packet to the specified mac address.
+ */
+void
+libvarpd_inject_arp(varpd_provider_handle_t *vph, const uint16_t vlan,
+ const uint8_t *srcmac, const struct in_addr *srcip, const uint8_t *dstmac)
+{
+ char buf[500];
+ size_t bsize = 0;
+ struct ether_arp *ea;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ if (vlan != 0) {
+ struct ether_vlan_header *eh;
+ eh = (struct ether_vlan_header *)(buf + bsize);
+ bsize += sizeof (struct ether_vlan_header);
+ bcopy(dstmac, &eh->ether_dhost, ETHERADDRL);
+ bcopy(srcmac, &eh->ether_shost, ETHERADDRL);
+ eh->ether_tpid = htons(ETHERTYPE_VLAN);
+ eh->ether_tci = htons(VLAN_TCI(0, ETHER_CFI, vlan));
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ } else {
+ struct ether_header *eh;
+ eh = (struct ether_header *)(buf + bsize);
+ bsize += sizeof (struct ether_header);
+ bcopy(dstmac, &eh->ether_dhost, ETHERADDRL);
+ bcopy(srcmac, &eh->ether_shost, ETHERADDRL);
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ }
+
+ ea = (struct ether_arp *)(buf + bsize);
+ bsize += sizeof (struct ether_arp);
+ ea->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+ ea->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+ ea->ea_hdr.ar_hln = ETHERADDRL;
+ ea->ea_hdr.ar_pln = sizeof (struct in_addr);
+ ea->ea_hdr.ar_op = htons(ARPOP_REQUEST);
+ bcopy(srcmac, ea->arp_sha, ETHERADDRL);
+ bcopy(srcip, ea->arp_spa, sizeof (struct in_addr));
+ bcopy(libvarpd_arp_bcast, ea->arp_tha, ETHERADDRL);
+ bcopy(srcip, ea->arp_tpa, sizeof (struct in_addr));
+
+ (void) libvarpd_overlay_instance_inject(inst, buf, bsize);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c
new file mode 100644
index 0000000000..b0fa907386
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c
@@ -0,0 +1,626 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd client interfaces
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <umem.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <door.h>
+
+#include <libvarpd_impl.h>
+
+typedef struct varpd_client {
+ int vcl_doorfd;
+} varpd_client_t;
+
+typedef struct varpd_client_prop_info {
+ varpd_client_t *vcprop_client;
+ uint64_t vcprop_instance;
+ uint_t vcprop_propid;
+ uint_t vcprop_type;
+ uint_t vcprop_prot;
+ uint32_t vcprop_defsize;
+ uint32_t vcprop_psize;
+ char vcprop_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vcprop_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vcprop_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_client_prop_info_t;
+
+static int
+libvarpd_c_door_call(varpd_client_t *client, varpd_client_arg_t *argp,
+ size_t altsize)
+{
+ int ret;
+ door_arg_t darg;
+
+ darg.data_ptr = (char *)argp;
+ darg.desc_ptr = NULL;
+ darg.desc_num = 0;
+ darg.rbuf = (char *)argp;
+ if (altsize != 0) {
+ darg.data_size = altsize;
+ darg.rsize = altsize;
+ } else {
+ darg.data_size = sizeof (varpd_client_arg_t);
+ darg.rsize = sizeof (varpd_client_arg_t);
+ }
+
+ do {
+ ret = door_call(client->vcl_doorfd, &darg);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0) {
+ switch (errno) {
+ case E2BIG:
+ case EFAULT:
+ case EINVAL:
+ case ENOTSUP:
+ case EOVERFLOW:
+ case ENFILE:
+ libvarpd_panic("unhandalable errno from door_call: %d",
+ errno);
+ }
+ ret = errno;
+ }
+
+ return (ret);
+}
+
+int
+libvarpd_c_create(varpd_client_handle_t **chpp, const char *doorname)
+{
+ varpd_client_t *client;
+
+ client = umem_alloc(sizeof (varpd_client_t), UMEM_DEFAULT);
+ if (client == NULL)
+ return (ENOMEM);
+
+ client->vcl_doorfd = open(doorname, O_RDWR);
+ if (client->vcl_doorfd < 0) {
+ int ret = errno;
+ umem_free(client, sizeof (varpd_client_t));
+ return (ret);
+ }
+
+ *chpp = (varpd_client_handle_t *)client;
+ return (0);
+}
+
+void
+libvarpd_c_destroy(varpd_client_handle_t *chp)
+{
+ varpd_client_t *client = (varpd_client_t *)chp;
+ if (close(client->vcl_doorfd) != 0)
+ libvarpd_panic("failed to close door fd %d: %d",
+ client->vcl_doorfd, errno);
+
+ umem_free(chp, sizeof (varpd_client_handle_t *));
+}
+
+int
+libvarpd_c_instance_create(varpd_client_handle_t *chp, datalink_id_t linkid,
+ const char *search, uint64_t *cidp)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_create_arg_t *cap = &carg.vca_un.vca_create;
+
+ if (strlen(search) >= LIBVARPD_PROP_NAMELEN)
+ return (EINVAL);
+ carg.vca_command = VARPD_CLIENT_CREATE;
+ carg.vca_errno = 0;
+ cap->vcca_linkid = linkid;
+ (void) strlcpy(cap->vcca_plugin, search, LIBVARPD_PROP_NAMELEN);
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ *cidp = cap->vcca_id;
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_activate(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance;
+
+ carg.vca_command = VARPD_CLIENT_ACTIVATE;
+ carg.vca_errno = 0;
+ vciap->vcia_id = cid;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_destroy(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance;
+
+ carg.vca_command = VARPD_CLIENT_DESTROY;
+ carg.vca_errno = 0;
+ vciap->vcia_id = cid;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_prop_nprops(varpd_client_handle_t *chp, uint64_t cid, uint_t *nprops)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_nprops_arg_t *vcnap = &carg.vca_un.vca_nprops;
+
+ carg.vca_command = VARPD_CLIENT_NPROPS;
+ carg.vca_errno = 0;
+ vcnap->vcna_id = cid;
+ vcnap->vcna_nprops = 0;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ *nprops = vcnap->vcna_nprops;
+ return (0);
+}
+
+int
+libvarpd_c_prop_handle_alloc(varpd_client_handle_t *chp, uint64_t cid,
+ varpd_client_prop_handle_t **phdlp)
+{
+ varpd_client_prop_info_t *infop;
+
+ infop = umem_alloc(sizeof (varpd_client_prop_info_t), UMEM_DEFAULT);
+ if (infop == NULL)
+ return (ENOMEM);
+
+ bzero(infop, sizeof (varpd_client_prop_info_t));
+ infop->vcprop_client = (varpd_client_t *)chp;
+ infop->vcprop_instance = cid;
+ infop->vcprop_propid = UINT_MAX;
+ *phdlp = (varpd_client_prop_handle_t *)infop;
+ return (0);
+}
+
+void
+libvarpd_c_prop_handle_free(varpd_client_prop_handle_t *phdl)
+{
+ umem_free(phdl, sizeof (varpd_client_prop_info_t));
+ phdl = NULL;
+}
+
+static void
+libvarpd_c_prop_info_from_door(varpd_client_prop_info_t *infop,
+ const varpd_client_propinfo_arg_t *vcfap)
+{
+ infop->vcprop_propid = vcfap->vcfa_propid;
+ infop->vcprop_type = vcfap->vcfa_type;
+ infop->vcprop_prot = vcfap->vcfa_prot;
+ infop->vcprop_defsize = vcfap->vcfa_defsize;
+ infop->vcprop_psize = vcfap->vcfa_psize;
+ bcopy(vcfap->vcfa_name, infop->vcprop_name, LIBVARPD_PROP_NAMELEN);
+ bcopy(vcfap->vcfa_default, infop->vcprop_default,
+ LIBVARPD_PROP_SIZEMAX);
+ bcopy(vcfap->vcfa_poss, infop->vcprop_poss, LIBVARPD_PROP_SIZEMAX);
+}
+
+int
+libvarpd_c_prop_info_fill_by_name(varpd_client_prop_handle_t *phdl,
+ const char *name)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (strlen(name) >= LIBVARPD_PROP_NAMELEN)
+ return (EINVAL);
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_PROPINFO;
+ carg.vca_errno = 0;
+ vcfap->vcfa_id = infop->vcprop_instance;
+ vcfap->vcfa_propid = UINT_MAX;
+ (void) strlcpy(vcfap->vcfa_name, name, LIBVARPD_PROP_NAMELEN);
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ libvarpd_c_prop_info_from_door(infop, vcfap);
+ return (0);
+}
+
+int
+libvarpd_c_prop_info_fill(varpd_client_prop_handle_t *phdl, uint_t propid)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_PROPINFO;
+ carg.vca_errno = 0;
+ vcfap->vcfa_id = infop->vcprop_instance;
+ vcfap->vcfa_propid = propid;
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ libvarpd_c_prop_info_from_door(infop, vcfap);
+ return (0);
+}
+
+int
+libvarpd_c_prop_info(varpd_client_prop_handle_t *phdl, const char **namep,
+ uint_t *typep, uint_t *protp, const void **defp, uint32_t *defsizep,
+ const mac_propval_range_t **possp)
+{
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+ if (infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+
+ if (namep != NULL)
+ *namep = infop->vcprop_name;
+ if (typep != NULL)
+ *typep = infop->vcprop_type;
+ if (protp != NULL)
+ *protp = infop->vcprop_prot;
+ if (defp != NULL)
+ *defp = infop->vcprop_default;
+ if (defsizep != NULL)
+ *defsizep = infop->vcprop_defsize;
+ if (possp != NULL)
+ *possp = (const mac_propval_range_t *)infop->vcprop_poss;
+ return (0);
+}
+
+int
+libvarpd_c_prop_get(varpd_client_prop_handle_t *phdl, void *buf, uint32_t *len)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (len == NULL || buf == NULL || infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+ if (*len < LIBVARPD_PROP_SIZEMAX)
+ return (EOVERFLOW);
+
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_GETPROP;
+ carg.vca_errno = 0;
+ vcpap->vcpa_id = infop->vcprop_instance;
+ vcpap->vcpa_propid = infop->vcprop_propid;
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ /*
+ * If the buffer size is too large then something odd has certainly
+ * happened here, it means that varpd has gone rogue. In such a case we
+ * return a rather odd errror, though we don't believe that this should
+ * generally happen.
+ */
+ if (vcpap->vcpa_bufsize > LIBVARPD_PROP_SIZEMAX)
+ return (E2BIG);
+
+ bcopy(vcpap->vcpa_buf, buf, vcpap->vcpa_bufsize);
+ *len = vcpap->vcpa_bufsize;
+ return (0);
+}
+
+int
+libvarpd_c_prop_set(varpd_client_prop_handle_t *phdl, const void *buf,
+ uint32_t len)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (len == NULL || buf == NULL || infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+ if (len > LIBVARPD_PROP_SIZEMAX)
+ return (EOVERFLOW);
+
+ carg.vca_command = VARPD_CLIENT_SETPROP;
+ carg.vca_errno = 0;
+ vcpap->vcpa_id = infop->vcprop_instance;
+ vcpap->vcpa_propid = infop->vcprop_propid;
+ vcpap->vcpa_bufsize = len;
+ bcopy(buf, vcpap->vcpa_buf, len);
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_lookup(varpd_client_handle_t *chp, datalink_id_t linkid,
+ uint64_t *instp)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_lookup_arg_t *vclap = &carg.vca_un.vca_lookup;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_LOOKUP;
+ carg.vca_errno = 0;
+ vclap->vcla_linkid = linkid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ if (instp != NULL)
+ *instp = vclap->vcla_id;
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_target_mode(varpd_client_handle_t *chp, uint64_t cid,
+ uint_t *dtype, uint_t *mtype)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_mode_arg_t *vctmap = &carg.vca_un.vca_mode;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_TARGET_MODE;
+ carg.vca_errno = 0;
+ vctmap->vtma_id = cid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ if (ret == 0) {
+ if (mtype != NULL)
+ *mtype = vctmap->vtma_mode;
+ if (dtype != NULL)
+ *dtype = vctmap->vtma_dest;
+ }
+
+ return (ret);
+}
+
+int
+libvarpd_c_instance_cache_flush(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_CACHE_FLUSH;
+ carg.vca_errno = 0;
+
+ vctcap->vtca_id = cid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_delete(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_DELETE;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_get(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key, varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL || entry == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_GET;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+ bzero(&vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t));
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ bcopy(&vctcap->vtca_entry, entry, sizeof (varpd_client_cache_entry_t));
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_set(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key, const varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL || entry == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_SET;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+ bcopy(entry, &vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t));
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_walk(varpd_client_handle_t *chp, uint64_t cid,
+ varpd_client_cache_f func, void *arg)
+{
+ int ret = 0;
+ size_t bufsize = sizeof (varpd_client_arg_t) +
+ 100 * sizeof (varpd_client_cache_entry_t);
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t *cargp;
+ varpd_client_target_walk_arg_t *vctwap;
+
+ /*
+ * Because the number of entries involved in a walk may be large, we
+ * dynamically allocate a number of queries to make at a single time.
+ * This also means that the average door request doesn't inflate by the
+ * number of entries we want. For now, let's always grab 100 entries in
+ * a request.
+ */
+ cargp = umem_zalloc(bufsize, UMEM_DEFAULT);
+ if (cargp == NULL)
+ return (errno);
+ vctwap = &cargp->vca_un.vca_walk;
+ for (;;) {
+ int i;
+
+ cargp->vca_command = VARPD_CLIENT_CACHE_WALK;
+ cargp->vca_errno = 0;
+ vctwap->vtcw_id = cid;
+ vctwap->vtcw_count = 100;
+
+ ret = libvarpd_c_door_call(client, cargp, bufsize);
+ if (ret != 0)
+ break;
+
+ if (cargp->vca_errno != 0) {
+ ret = cargp->vca_errno;
+ break;
+ }
+
+ if (vctwap->vtcw_count == 0) {
+ ret = 0;
+ break;
+ }
+
+ for (i = 0; i < vctwap->vtcw_count; i++) {
+ varpd_client_cache_entry_t ent;
+
+ ent.vcp_flags = vctwap->vtcw_ents[i].otce_flags;
+ bcopy(vctwap->vtcw_ents[i].otce_dest.otp_mac,
+ &ent.vcp_mac, ETHERADDRL);
+ ent.vcp_ip = vctwap->vtcw_ents[i].otce_dest.otp_ip;
+ ent.vcp_port = vctwap->vtcw_ents[i].otce_dest.otp_port;
+ ret = func(chp, cid,
+ (struct ether_addr *)vctwap->vtcw_ents[i].otce_mac,
+ &ent, arg);
+ if (ret != 0) {
+ ret = 0;
+ goto done;
+ }
+ }
+ }
+
+done:
+ umem_free(cargp, bufsize);
+ return (ret);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h
new file mode 100644
index 0000000000..459711b385
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h
@@ -0,0 +1,92 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_CLIENT_H
+#define _LIBVARPD_CLIENT_H
+
+/*
+ * varpd interfaces
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/mac.h>
+#include <sys/overlay_target.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __varpd_client_handle varpd_client_handle_t;
+typedef struct __varpd_client_prop_handle varpd_client_prop_handle_t;
+
+typedef struct varpd_client_cache_entry {
+ struct ether_addr vcp_mac;
+ uint16_t vcp_flags;
+ struct in6_addr vcp_ip;
+ uint16_t vcp_port;
+} varpd_client_cache_entry_t;
+
+/*
+ * We just use the values from the kernel for now.
+ */
+#define LIBVARPD_PROP_SIZEMAX OVERLAY_PROP_SIZEMAX
+#define LIBVARPD_PROP_NAMELEN OVERLAY_PROP_NAMELEN
+
+extern int libvarpd_c_create(varpd_client_handle_t **, const char *);
+extern void libvarpd_c_destroy(varpd_client_handle_t *);
+extern int libvarpd_c_instance_create(varpd_client_handle_t *, datalink_id_t,
+ const char *, uint64_t *);
+extern int libvarpd_c_instance_activate(varpd_client_handle_t *, uint64_t);
+extern int libvarpd_c_instance_destroy(varpd_client_handle_t *, uint64_t);
+
+extern int libvarpd_c_prop_nprops(varpd_client_handle_t *, uint64_t, uint_t *);
+extern int libvarpd_c_prop_handle_alloc(varpd_client_handle_t *, uint64_t,
+ varpd_client_prop_handle_t **);
+extern void libvarpd_c_prop_handle_free(varpd_client_prop_handle_t *);
+extern int libvarpd_c_prop_info_fill(varpd_client_prop_handle_t *, uint_t);
+extern int libvarpd_c_prop_info_fill_by_name(varpd_client_prop_handle_t *,
+ const char *);
+extern int libvarpd_c_prop_info(varpd_client_prop_handle_t *, const char **,
+ uint_t *, uint_t *, const void **, uint32_t *,
+ const mac_propval_range_t **);
+extern int libvarpd_c_prop_get(varpd_client_prop_handle_t *, void *,
+ uint32_t *);
+extern int libvarpd_c_prop_set(varpd_client_prop_handle_t *, const void *,
+ uint32_t);
+
+extern int libvarpd_c_instance_lookup(varpd_client_handle_t *, datalink_id_t,
+ uint64_t *);
+extern int libvarpd_c_instance_target_mode(varpd_client_handle_t *, uint64_t,
+ uint_t *, uint_t *);
+extern int libvarpd_c_instance_cache_flush(varpd_client_handle_t *, uint64_t);
+extern int libvarpd_c_instance_cache_delete(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *);
+extern int libvarpd_c_instance_cache_get(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, varpd_client_cache_entry_t *);
+extern int libvarpd_c_instance_cache_set(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, const varpd_client_cache_entry_t *);
+
+typedef int (*varpd_client_cache_f)(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, const varpd_client_cache_entry_t *, void *);
+extern int libvarpd_c_instance_cache_walk(varpd_client_handle_t *, uint64_t,
+ varpd_client_cache_f, void *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_CLIENT_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c
new file mode 100644
index 0000000000..f684e031a8
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c
@@ -0,0 +1,469 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd door server logic
+ */
+
+#include <door.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <priv.h>
+#include <libvarpd_impl.h>
+
+typedef int (libvarpd_door_f)(varpd_impl_t *, varpd_client_arg_t *, ucred_t *);
+
+static boolean_t
+libvarpd_door_privileged(ucred_t *credp)
+{
+ const priv_set_t *ps;
+
+ ps = ucred_getprivset(credp, PRIV_EFFECTIVE);
+ if (ps == NULL)
+ return (B_FALSE);
+
+ return (priv_ismember(ps, PRIV_SYS_NET_CONFIG));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_create(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihdl;
+ varpd_client_create_arg_t *vccap = &vcap->vca_un.vca_create;
+
+ vccap->vcca_plugin[LIBVARPD_PROP_NAMELEN-1] = '\0';
+ ret = libvarpd_instance_create((varpd_handle_t *)vip,
+ vccap->vcca_linkid, vccap->vcca_plugin, &ihdl);
+ if (ret == 0)
+ vccap->vcca_id = libvarpd_instance_id(ihdl);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_activate(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_instance_activate(ihp));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_destroy(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ libvarpd_instance_destroy(ihp);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_nprops(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_nprops_arg_t *vcnap = &vcap->vca_un.vca_nprops;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcnap->vcna_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_prop_nprops(ihp, &vcnap->vcna_nprops));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_propinfo(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_propinfo_arg_t *vcfap = &vcap->vca_un.vca_info;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcfap->vcfa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ if (vcfap->vcfa_propid != UINT_MAX) {
+ ret = libvarpd_prop_info_fill(phdl, vcfap->vcfa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ } else {
+ uint_t i, nprop;
+ const char *name;
+
+ vcfap->vcfa_name[LIBVARPD_PROP_NAMELEN-1] = '\0';
+ ret = libvarpd_prop_nprops(ihp, &nprop);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ for (i = 0; i < nprop; i++) {
+ ret = libvarpd_prop_info_fill(phdl, i);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ ret = libvarpd_prop_info(phdl, &name, NULL, NULL, NULL,
+ NULL, NULL);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ if (strcmp(vcfap->vcfa_name, name) == 0)
+ break;
+ }
+
+ if (i == nprop) {
+ libvarpd_prop_handle_free(phdl);
+ return (ENOENT);
+ }
+ vcfap->vcfa_propid = i;
+ }
+ libvarpd_prop_door_convert(phdl, vcfap);
+ libvarpd_prop_handle_free(phdl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_getprop(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ uint32_t size;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+
+ ret = libvarpd_prop_get(phdl, vcpap->vcpa_buf, &size);
+ if (ret == 0)
+ vcpap->vcpa_bufsize = size;
+ libvarpd_prop_handle_free(phdl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_setprop(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+
+ ret = libvarpd_prop_set(phdl, vcpap->vcpa_buf, vcpap->vcpa_bufsize);
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_lookup(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_t *inst;
+ varpd_client_lookup_arg_t *vclap = &vcap->vca_un.vca_lookup;
+
+ inst = libvarpd_instance_lookup_by_dlid(vip, vclap->vcla_linkid);
+ if (inst == NULL)
+ return (ENOENT);
+
+ vclap->vcla_id = inst->vri_id;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_target(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_instance_t *inst;
+ varpd_client_target_mode_arg_t *vtmap = &vcap->vca_un.vca_mode;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtmap->vtma_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ inst = (varpd_instance_t *)ihp;
+ vtmap->vtma_dest = inst->vri_dest;
+ vtmap->vtma_mode = inst->vri_mode;
+ return (0);
+}
+
+static int
+libvarpd_door_f_flush(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_flush((varpd_instance_t *)ihp));
+}
+
+static int
+libvarpd_door_f_delete(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_delete((varpd_instance_t *)ihp,
+ vtcap->vtca_key));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_get(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_get((varpd_instance_t *)ihp,
+ vtcap->vtca_key, &vtcap->vtca_entry));
+}
+
+static int
+libvarpd_door_f_set(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_overlay_cache_set((varpd_instance_t *)ihp,
+ vtcap->vtca_key, &vtcap->vtca_entry));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_walk(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_walk_arg_t *vctwp = &vcap->vca_un.vca_walk;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vctwp->vtcw_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_overlay_cache_walk_fill((varpd_instance_t *)ihp,
+ &vctwp->vtcw_marker, &vctwp->vtcw_count, vctwp->vtcw_ents));
+}
+
+static libvarpd_door_f *libvarpd_door_table[] = {
+ libvarpd_door_f_create,
+ libvarpd_door_f_activate,
+ libvarpd_door_f_destroy,
+ libvarpd_door_f_nprops,
+ libvarpd_door_f_propinfo,
+ libvarpd_door_f_getprop,
+ libvarpd_door_f_setprop,
+ libvarpd_door_f_lookup,
+ libvarpd_door_f_target,
+ libvarpd_door_f_flush,
+ libvarpd_door_f_delete,
+ libvarpd_door_f_get,
+ libvarpd_door_f_set,
+ libvarpd_door_f_walk
+};
+
+/* ARGSUSED */
+static void
+libvarpd_door_server(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
+ uint_t ndesc)
+{
+ int ret;
+ varpd_client_eresp_t err;
+ ucred_t *credp = NULL;
+ varpd_impl_t *vip = cookie;
+ varpd_client_arg_t *vcap = (varpd_client_arg_t *)argp;
+
+ err.vce_command = VARPD_CLIENT_INVALID;
+ if (argsz < sizeof (varpd_client_arg_t)) {
+ err.vce_errno = EINVAL;
+ goto errout;
+ }
+
+ if ((ret = door_ucred(&credp)) != 0) {
+ err.vce_errno = ret;
+ goto errout;
+ }
+
+ if (vcap->vca_command == VARPD_CLIENT_INVALID ||
+ vcap->vca_command >= VARPD_CLIENT_MAX) {
+ err.vce_errno = EINVAL;
+ goto errout;
+ }
+
+ vcap->vca_errno = 0;
+ ret = libvarpd_door_table[vcap->vca_command - 1](vip, vcap, credp);
+ if (ret != 0)
+ vcap->vca_errno = ret;
+
+ ucred_free(credp);
+ (void) door_return(argp, argsz, NULL, 0);
+ return;
+
+errout:
+ ucred_free(credp);
+ (void) door_return((char *)&err, sizeof (err), NULL, 0);
+}
+
+int
+libvarpd_door_server_create(varpd_handle_t *vhp, const char *path)
+{
+ int fd, ret;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_doorfd >= 0) {
+ mutex_exit(&vip->vdi_lock);
+ return (EEXIST);
+ }
+
+ vip->vdi_doorfd = door_create(libvarpd_door_server, vip,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+ if (vip->vdi_doorfd == -1) {
+ mutex_exit(&vip->vdi_lock);
+ return (errno);
+ }
+
+ if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (errno);
+ }
+
+ if (fchown(fd, UID_NETADM, GID_NETADM) != 0) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (ret);
+ }
+
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close door fd %d: %d",
+ fd, errno);
+ (void) fdetach(path);
+ if (fattach(vip->vdi_doorfd, path) != 0) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (ret);
+ }
+
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+}
+
+void
+libvarpd_door_server_destroy(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_doorfd != 0) {
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ vip->vdi_doorfd = -1;
+ }
+ mutex_exit(&vip->vdi_lock);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h
new file mode 100644
index 0000000000..7ecd3a952f
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h
@@ -0,0 +1,247 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_IMPL_H
+#define _LIBVARPD_IMPL_H
+
+/*
+ * varpd internal interfaces
+ */
+
+#include <libvarpd.h>
+#include <libvarpd_provider.h>
+#include <sys/avl.h>
+#include <thread.h>
+#include <synch.h>
+#include <limits.h>
+#include <libidspace.h>
+#include <umem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBVARPD_ID_MIN 1
+#define LIBVARPD_ID_MAX INT32_MAX
+
+typedef struct varpd_plugin {
+ avl_node_t vpp_node;
+ const char *vpp_name;
+ overlay_target_mode_t vpp_mode;
+ const varpd_plugin_ops_t *vpp_ops;
+ mutex_t vpp_lock;
+ uint_t vpp_active;
+} varpd_plugin_t;
+
+typedef struct varpd_impl {
+ mutex_t vdi_lock;
+ rwlock_t vdi_pfdlock;
+ avl_tree_t vdi_plugins; /* vdi_lock */
+ avl_tree_t vdi_instances; /* vdi_lock */
+ avl_tree_t vdi_linstances; /* vdi_lock */
+ id_space_t *vdi_idspace; /* RO */
+ umem_cache_t *vdi_qcache; /* RO */
+ bunyan_logger_t *vdi_bunyan; /* RO */
+ int vdi_overlayfd; /* RO */
+ int vdi_doorfd; /* vdi_lock */
+ int vdi_persistfd; /* vdi_plock */
+ cond_t vdi_lthr_cv; /* vdi_lock */
+ boolean_t vdi_lthr_quiesce; /* vdi_lock */
+ uint_t vdi_lthr_count; /* vdi_lock */
+} varpd_impl_t;
+
+typedef enum varpd_instance_flags {
+ VARPD_INSTANCE_F_ACTIVATED = 0x01
+} varpd_instance_flags_t;
+
+typedef struct varpd_instance {
+ avl_node_t vri_inode;
+ avl_node_t vri_lnode;
+ uint64_t vri_id; /* RO */
+ uint64_t vri_vnetid; /* RO */
+ datalink_id_t vri_linkid; /* RO */
+ overlay_target_mode_t vri_mode; /* RO */
+ overlay_plugin_dest_t vri_dest; /* RO */
+ varpd_impl_t *vri_impl; /* RO */
+ varpd_plugin_t *vri_plugin; /* RO */
+ void *vri_private; /* RO */
+ mutex_t vri_lock;
+ varpd_instance_flags_t vri_flags; /* vri_lock */
+} varpd_instance_t;
+
+typedef struct varpd_query {
+ overlay_targ_lookup_t vq_lookup;
+ overlay_targ_resp_t vq_response;
+ varpd_instance_t *vq_instance;
+} varpd_query_t;
+
+typedef struct varpd_client_create_arg {
+ datalink_id_t vcca_linkid;
+ uint64_t vcca_id;
+ char vcca_plugin[LIBVARPD_PROP_NAMELEN];
+} varpd_client_create_arg_t;
+
+typedef struct varpd_client_instance_arg {
+ uint64_t vcia_id;
+} varpd_client_instance_arg_t;
+
+typedef struct varpd_client_nprops_arg {
+ uint64_t vcna_id;
+ uint_t vcna_nprops;
+} varpd_client_nprops_arg_t;
+
+typedef struct varpd_client_propinfo_arg {
+ uint64_t vcfa_id;
+ uint_t vcfa_propid;
+ uint_t vcfa_type;
+ uint_t vcfa_prot;
+ uint32_t vcfa_defsize;
+ uint32_t vcfa_psize;
+ char vcfa_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vcfa_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vcfa_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_client_propinfo_arg_t;
+
+typedef struct varpd_client_prop_arg {
+ uint64_t vcpa_id;
+ uint_t vcpa_propid;
+ uint8_t vcpa_buf[LIBVARPD_PROP_SIZEMAX];
+ size_t vcpa_bufsize;
+} varpd_client_prop_arg_t;
+
+typedef struct varpd_client_lookup_arg {
+ datalink_id_t vcla_linkid;
+ uint32_t vcla_pad;
+ uint64_t vcla_id;
+} varpd_client_lookup_arg_t;
+
+typedef struct varpd_client_target_mode_arg {
+ uint64_t vtma_id;
+ uint32_t vtma_dest;
+ uint32_t vtma_mode;
+} varpd_client_target_mode_arg_t;
+
+typedef struct varpd_client_target_cache_arg {
+ uint64_t vtca_id;
+ uint8_t vtca_key[ETHERADDRL];
+ uint8_t vtca_pad[2];
+ varpd_client_cache_entry_t vtca_entry;
+} varpd_client_target_cache_arg_t;
+
+typedef struct varpd_client_target_walk_arg {
+ uint64_t vtcw_id;
+ uint64_t vtcw_marker;
+ uint64_t vtcw_count;
+ overlay_targ_cache_entry_t vtcw_ents[];
+} varpd_client_target_walk_arg_t;
+
+typedef enum varpd_client_command {
+ VARPD_CLIENT_INVALID = 0x0,
+ VARPD_CLIENT_CREATE,
+ VARPD_CLIENT_ACTIVATE,
+ VARPD_CLIENT_DESTROY,
+ VARPD_CLIENT_NPROPS,
+ VARPD_CLIENT_PROPINFO,
+ VARPD_CLIENT_GETPROP,
+ VARPD_CLIENT_SETPROP,
+ VARPD_CLIENT_LOOKUP,
+ VARPD_CLIENT_TARGET_MODE,
+ VARPD_CLIENT_CACHE_FLUSH,
+ VARPD_CLIENT_CACHE_DELETE,
+ VARPD_CLIENT_CACHE_GET,
+ VARPD_CLIENT_CACHE_SET,
+ VARPD_CLIENT_CACHE_WALK,
+ VARPD_CLIENT_MAX
+} varpd_client_command_t;
+
+typedef struct varpd_client_arg {
+ uint_t vca_command;
+ uint_t vca_errno;
+ union {
+ varpd_client_create_arg_t vca_create;
+ varpd_client_instance_arg_t vca_instance;
+ varpd_client_nprops_arg_t vca_nprops;
+ varpd_client_propinfo_arg_t vca_info;
+ varpd_client_prop_arg_t vca_prop;
+ varpd_client_lookup_arg_t vca_lookup;
+ varpd_client_target_mode_arg_t vca_mode;
+ varpd_client_target_cache_arg_t vca_cache;
+ varpd_client_target_walk_arg_t vca_walk;
+ } vca_un;
+} varpd_client_arg_t;
+
+typedef struct varpd_client_eresp {
+ uint_t vce_command;
+ uint_t vce_errno;
+} varpd_client_eresp_t;
+
+extern void libvarpd_plugin_init(void);
+extern void libvarpd_plugin_prefork(void);
+extern void libvarpd_plugin_postfork(void);
+extern void libvarpd_plugin_fini(void);
+extern int libvarpd_plugin_comparator(const void *, const void *);
+extern varpd_plugin_t *libvarpd_plugin_lookup(varpd_impl_t *, const char *);
+
+extern varpd_instance_t *libvarpd_instance_lookup_by_dlid(varpd_impl_t *,
+ datalink_id_t);
+
+extern void libvarpd_prop_door_convert(const varpd_prop_handle_t *,
+ varpd_client_propinfo_arg_t *);
+
+extern const char *libvarpd_isaext(void);
+typedef int (*libvarpd_dirwalk_f)(varpd_impl_t *, const char *, void *);
+extern int libvarpd_dirwalk(varpd_impl_t *, const char *, const char *,
+ libvarpd_dirwalk_f, void *);
+
+extern int libvarpd_overlay_init(varpd_impl_t *);
+extern void libvarpd_overlay_fini(varpd_impl_t *);
+extern int libvarpd_overlay_info(varpd_impl_t *, datalink_id_t,
+ overlay_plugin_dest_t *, uint64_t *, uint64_t *);
+extern int libvarpd_overlay_associate(varpd_instance_t *);
+extern int libvarpd_overlay_disassociate(varpd_instance_t *);
+extern int libvarpd_overlay_degrade(varpd_instance_t *, const char *);
+extern int libvarpd_overlay_degrade_datalink(varpd_impl_t *, datalink_id_t,
+ const char *);
+extern int libvarpd_overlay_restore(varpd_instance_t *);
+extern int libvarpd_overlay_packet(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t *);
+extern int libvarpd_overlay_inject(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t);
+extern int libvarpd_overlay_instance_inject(varpd_instance_t *, void *, size_t);
+extern int libvarpd_overlay_resend(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t);
+typedef int (*libvarpd_overlay_iter_f)(varpd_impl_t *, datalink_id_t, void *);
+extern int libvarpd_overlay_iter(varpd_impl_t *, libvarpd_overlay_iter_f,
+ void *);
+extern int libvarpd_overlay_cache_flush(varpd_instance_t *);
+extern int libvarpd_overlay_cache_delete(varpd_instance_t *, const uint8_t *);
+extern int libvarpd_overlay_cache_delete(varpd_instance_t *, const uint8_t *);
+extern int libvarpd_overlay_cache_get(varpd_instance_t *, const uint8_t *,
+ varpd_client_cache_entry_t *);
+extern int libvarpd_overlay_cache_set(varpd_instance_t *, const uint8_t *,
+ const varpd_client_cache_entry_t *);
+extern int libvarpd_overlay_cache_walk_fill(varpd_instance_t *, uint64_t *,
+ uint64_t *, overlay_targ_cache_entry_t *);
+
+extern void libvarpd_persist_init(varpd_impl_t *);
+extern void libvarpd_persist_fini(varpd_impl_t *);
+extern int libvarpd_persist_instance(varpd_impl_t *, varpd_instance_t *);
+extern void libvarpd_torch_instance(varpd_impl_t *, varpd_instance_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_IMPL_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c
new file mode 100644
index 0000000000..b7506c56cf
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c
@@ -0,0 +1,584 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Interactions with /dev/overlay
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <strings.h>
+#include <umem.h>
+
+#include <libvarpd_impl.h>
+#include <sys/overlay_target.h>
+
+#define OVERLAY_PATH "/dev/overlay"
+
+int
+libvarpd_overlay_init(varpd_impl_t *vip)
+{
+ vip->vdi_overlayfd = open(OVERLAY_PATH, O_RDWR | O_EXCL);
+ if (vip->vdi_overlayfd == -1)
+ return (errno);
+ return (0);
+}
+
+void
+libvarpd_overlay_fini(varpd_impl_t *vip)
+{
+ assert(vip->vdi_overlayfd > 0);
+ if (close(vip->vdi_overlayfd) != 0)
+ libvarpd_panic("failed to close /dev/overlay fd %d: %d",
+ vip->vdi_overlayfd, errno);
+}
+
+int
+libvarpd_overlay_info(varpd_impl_t *vip, datalink_id_t linkid,
+ overlay_plugin_dest_t *destp, uint64_t *flags, uint64_t *vnetid)
+{
+ overlay_targ_info_t oti;
+
+ oti.oti_linkid = linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_INFO, &oti) != 0)
+ return (errno);
+
+ if (destp != NULL)
+ *destp = oti.oti_needs;
+ if (flags != NULL)
+ *flags = oti.oti_flags;
+ if (vnetid != NULL)
+ *vnetid = oti.oti_vnetid;
+ return (0);
+}
+
+int
+libvarpd_overlay_associate(varpd_instance_t *inst)
+{
+ overlay_targ_associate_t ota;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&ota, sizeof (overlay_targ_associate_t));
+ ota.ota_linkid = inst->vri_linkid;
+ ota.ota_mode = inst->vri_mode;
+ ota.ota_id = inst->vri_id;
+ ota.ota_provides = inst->vri_dest;
+
+ if (ota.ota_mode == OVERLAY_TARGET_POINT) {
+ int ret;
+ ret = inst->vri_plugin->vpp_ops->vpo_default(inst->vri_private,
+ &ota.ota_point);
+ if (ret != VARPD_LOOKUP_OK)
+ return (ret);
+ }
+
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_ASSOCIATE, &ota) != 0)
+ return (errno);
+
+ return (0);
+}
+
+int
+libvarpd_overlay_disassociate(varpd_instance_t *inst)
+{
+ overlay_targ_id_t otid;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ otid.otid_linkid = inst->vri_linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DISASSOCIATE, &otid) != 0)
+ return (errno);
+ return (0);
+}
+
+int
+libvarpd_overlay_degrade_datalink(varpd_impl_t *vip, datalink_id_t linkid,
+ const char *msg)
+{
+ overlay_targ_degrade_t otd;
+
+ otd.otd_linkid = linkid;
+ (void) strlcpy(otd.otd_buf, msg, OVERLAY_STATUS_BUFLEN);
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DEGRADE, &otd) != 0)
+ return (errno);
+ return (0);
+
+}
+
+int
+libvarpd_overlay_degrade(varpd_instance_t *inst, const char *msg)
+{
+ return (libvarpd_overlay_degrade_datalink(inst->vri_impl,
+ inst->vri_linkid, msg));
+}
+
+int
+libvarpd_overlay_restore(varpd_instance_t *inst)
+{
+ overlay_targ_id_t otid;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ otid.otid_linkid = inst->vri_linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_RESTORE, &otid) != 0)
+ return (errno);
+ return (0);
+}
+
+int
+libvarpd_overlay_packet(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t *buflen)
+{
+ int ret;
+ overlay_targ_pkt_t otp;
+
+ otp.otp_linkid = UINT64_MAX;
+ otp.otp_reqid = otl->otl_reqid;
+ otp.otp_size = *buflen;
+ otp.otp_buf = buf;
+
+ do {
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_PKT, &otp);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_PKT ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ if (ret == 0)
+ *buflen = otp.otp_size;
+
+ return (ret);
+}
+
+static int
+libvarpd_overlay_inject_common(varpd_impl_t *vip, varpd_instance_t *inst,
+ const overlay_targ_lookup_t *otl, void *buf, size_t buflen, int cmd)
+{
+ int ret;
+ overlay_targ_pkt_t otp;
+
+ if (otl == NULL) {
+ otp.otp_linkid = inst->vri_linkid;
+ otp.otp_reqid = 0;
+ } else {
+ otp.otp_linkid = UINT64_MAX;
+ otp.otp_reqid = otl->otl_reqid;
+ }
+ otp.otp_size = buflen;
+ otp.otp_buf = buf;
+
+ do {
+ ret = ioctl(vip->vdi_overlayfd, cmd, &otp);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("overlay_inject_common ioctl EFAULT");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+}
+
+int
+libvarpd_overlay_inject(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
+ OVERLAY_TARG_INJECT));
+}
+
+int
+libvarpd_overlay_instance_inject(varpd_instance_t *inst, void *buf,
+ size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(inst->vri_impl, inst, NULL, buf,
+ buflen, OVERLAY_TARG_INJECT));
+}
+
+int
+libvarpd_overlay_resend(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
+ OVERLAY_TARG_RESEND));
+}
+
+static void
+libvarpd_overlay_lookup_reply(varpd_impl_t *vip,
+ const overlay_targ_lookup_t *otl, overlay_targ_resp_t *otr, int cmd)
+{
+ int ret;
+
+ otr->otr_reqid = otl->otl_reqid;
+ do {
+ ret = ioctl(vip->vdi_overlayfd, cmd, otr);
+ } while (ret != 0 && errno == EINTR);
+
+ /*
+ * The only errors that should cause us to end up here are due to
+ * programmer errors. Aruably the EINAVL case indicates that something
+ * is a bit off; however, at this time we don't opt to kill varpd.
+ */
+ if (ret != 0 && errno != EINVAL)
+ libvarpd_panic("receieved bad errno from lookup_reply "
+ "(cmd %d): %d\n", cmd, errno);
+}
+
+static void
+libvarpd_overlay_lookup_handle(varpd_impl_t *vip)
+{
+ int ret;
+ varpd_query_t *vqp;
+ overlay_targ_lookup_t *otl;
+ overlay_targ_resp_t *otr;
+ varpd_instance_t *inst;
+
+ vqp = umem_cache_alloc(vip->vdi_qcache, UMEM_DEFAULT);
+ otl = &vqp->vq_lookup;
+ otr = &vqp->vq_response;
+ /*
+ * abort doesn't really help here that much, maybe we can instead try
+ * and for a reap or something?
+ */
+ if (vqp == NULL)
+ libvarpd_panic("failed to allocate memory for lookup "
+ "handle..., we should not panic()");
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LOOKUP, otl);
+ if (ret != 0 && errno != ETIME && errno != EINTR)
+ libvarpd_panic("received bad errno from OVERLAY_TARG_LOOKUP: "
+ "%d", errno);
+
+ if (ret != 0) {
+ umem_cache_free(vip->vdi_qcache, vqp);
+ return;
+ }
+
+ inst = (varpd_instance_t *)libvarpd_instance_lookup(
+ (varpd_handle_t *)vip, otl->otl_varpdid);
+ if (inst == NULL) {
+ libvarpd_overlay_lookup_reply(vip, otl, otr,
+ OVERLAY_TARG_DROP);
+ umem_cache_free(vip->vdi_qcache, vqp);
+ return;
+ }
+ vqp->vq_instance = inst;
+
+ inst->vri_plugin->vpp_ops->vpo_lookup(inst->vri_private,
+ (varpd_query_handle_t *)vqp, otl, &otr->otr_answer);
+}
+
+void
+libvarpd_overlay_lookup_run(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_quiesce == B_TRUE) {
+ mutex_exit(&vip->vdi_lock);
+ return;
+ }
+ vip->vdi_lthr_count++;
+
+ for (;;) {
+ mutex_exit(&vip->vdi_lock);
+ libvarpd_overlay_lookup_handle(vip);
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_quiesce == B_TRUE)
+ break;
+ }
+ assert(vip->vdi_lthr_count > 0);
+ vip->vdi_lthr_count--;
+ (void) cond_signal(&vip->vdi_lthr_cv);
+ mutex_exit(&vip->vdi_lock);
+}
+
+void
+libvarpd_overlay_lookup_quiesce(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_count == 0) {
+ mutex_exit(&vip->vdi_lock);
+ return;
+ }
+ vip->vdi_lthr_quiesce = B_TRUE;
+ while (vip->vdi_lthr_count > 0)
+ (void) cond_wait(&vip->vdi_lthr_cv, &vip->vdi_lock);
+ vip->vdi_lthr_quiesce = B_FALSE;
+ mutex_exit(&vip->vdi_lock);
+}
+
+int
+libvarpd_overlay_iter(varpd_impl_t *vip, libvarpd_overlay_iter_f func,
+ void *arg)
+{
+ uint32_t curents = 0, i;
+ size_t size;
+ overlay_targ_list_t *otl;
+
+ for (;;) {
+ size = sizeof (overlay_targ_list_t) +
+ sizeof (uint32_t) * curents;
+ otl = umem_alloc(size, UMEM_DEFAULT);
+ if (otl == NULL)
+ return (ENOMEM);
+
+ otl->otl_nents = curents;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LIST, otl) != 0) {
+ if (errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_LIST ioctl "
+ "efault");
+ umem_free(otl, size);
+ if (errno == EINTR)
+ continue;
+ else
+ return (errno);
+ }
+
+ if (otl->otl_nents == curents)
+ break;
+
+ curents = otl->otl_nents;
+ umem_free(otl, size);
+ }
+
+ for (i = 0; i < otl->otl_nents; i++) {
+ if (func(vip, otl->otl_ents[i], arg) != 0)
+ break;
+ }
+ umem_free(otl, size);
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_flush(varpd_instance_t *inst)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_FLUSH, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_FLUSH ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+}
+
+int
+libvarpd_overlay_cache_delete(varpd_instance_t *inst, const uint8_t *key)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_REMOVE, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_REMOVE ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+
+}
+
+int
+libvarpd_overlay_cache_get(varpd_instance_t *inst, const uint8_t *key,
+ varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_GET, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_GET ioctl efault");
+ else if (ret != 0)
+ return (errno);
+
+ bcopy(cache.otc_entry.otce_dest.otp_mac, &entry->vcp_mac, ETHERADDRL);
+ entry->vcp_flags = cache.otc_entry.otce_flags;
+ entry->vcp_ip = cache.otc_entry.otce_dest.otp_ip;
+ entry->vcp_port = cache.otc_entry.otce_dest.otp_port;
+
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_set(varpd_instance_t *inst, const uint8_t *key,
+ const varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+ bcopy(&entry->vcp_mac, cache.otc_entry.otce_dest.otp_mac, ETHERADDRL);
+ cache.otc_entry.otce_flags = entry->vcp_flags;
+ cache.otc_entry.otce_dest.otp_ip = entry->vcp_ip;
+ cache.otc_entry.otce_dest.otp_port = entry->vcp_port;
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_SET ioctl efault");
+ else if (ret != 0)
+ return (errno);
+
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_walk_fill(varpd_instance_t *inst, uint64_t *markerp,
+ uint64_t *countp, overlay_targ_cache_entry_t *ents)
+{
+ int ret;
+ size_t asize;
+ overlay_targ_cache_iter_t *iter;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ if (*countp > 200)
+ return (E2BIG);
+
+ asize = sizeof (overlay_targ_cache_iter_t) +
+ *countp * sizeof (overlay_targ_cache_entry_t);
+ iter = umem_alloc(asize, UMEM_DEFAULT);
+ if (iter == NULL)
+ return (ENOMEM);
+
+ iter->otci_linkid = inst->vri_linkid;
+ iter->otci_marker = *markerp;
+ iter->otci_count = *countp;
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_ITER, iter);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_ITER ioctl efault");
+ else if (ret != 0) {
+ ret = errno;
+ goto out;
+ }
+
+ *markerp = iter->otci_marker;
+ *countp = iter->otci_count;
+ bcopy(iter->otci_ents, ents,
+ *countp * sizeof (overlay_targ_cache_entry_t));
+out:
+ umem_free(iter, asize);
+ return (ret);
+}
+
+void
+libvarpd_plugin_query_reply(varpd_query_handle_t *vqh, int action)
+{
+ varpd_query_t *vqp = (varpd_query_t *)vqh;
+
+ if (vqp == NULL)
+ libvarpd_panic("unkonwn plugin passed invalid "
+ "varpd_query_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP)
+ libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
+ &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_DROP);
+ else if (action == VARPD_LOOKUP_OK)
+ libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
+ &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_RESPOND);
+ else
+ libvarpd_panic("plugin %s passed in an invalid action: %d",
+ vqp->vq_instance->vri_plugin->vpp_name, action);
+}
+
+void
+libvarpd_inject_varp(varpd_provider_handle_t *vph, const uint8_t *mac,
+ const overlay_target_point_t *otp)
+{
+ int ret;
+ overlay_targ_cache_t otc;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ if (otp == NULL) {
+ (void) libvarpd_overlay_cache_delete(inst, mac);
+ return;
+ }
+
+ otc.otc_linkid = inst->vri_linkid;
+ otc.otc_entry.otce_flags = 0;
+ bcopy(mac, otc.otc_entry.otce_mac, ETHERADDRL);
+ bcopy(otp, &otc.otc_entry.otce_dest, sizeof (overlay_target_point_t));
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &otc);
+ if (ret != 0) {
+ switch (errno) {
+ case EBADF:
+ case EFAULT:
+ case ENOTSUP:
+ libvarpd_panic("received bad errno from "
+ "OVERLAY_TARG_CACHE_SET: %d", errno);
+ default:
+ break;
+ }
+ }
+}
+
+void
+libvarpd_fma_degrade(varpd_provider_handle_t *vph, const char *msg)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ ret = libvarpd_overlay_degrade(inst, msg);
+ switch (ret) {
+ case ENOENT:
+ case EFAULT:
+ libvarpd_panic("received bad errno from degrade ioctl: %d",
+ errno);
+ default:
+ break;
+ }
+}
+
+void
+libvarpd_fma_restore(varpd_provider_handle_t *vph)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ ret = libvarpd_overlay_restore(inst);
+ switch (ret) {
+ case ENOENT:
+ case EFAULT:
+ libvarpd_panic("received bad errno from restore ioctl: %d",
+ errno);
+ default:
+ break;
+ }
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c
new file mode 100644
index 0000000000..6728d79d6e
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * No, 'tis not so deep as a well, nor so wide as a church door; but 'tis
+ * enough,'twill serve. Ask for me tomorrow, and you shall find me a grave man.
+ *
+ * This file maintains various routines for handling when we die.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <thread.h>
+#include <stdlib.h>
+
+/*
+ * Normally these would be static, but if they're static, that throws off lint
+ * because it thinks we never use them, which is kind of the point, because we
+ * only read them in the core...
+ */
+int varpd_panic_errno;
+char varpd_panic_buf[1024];
+thread_t varpd_panic_thread;
+
+void
+libvarpd_panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ /* Always save errno first! */
+ varpd_panic_errno = errno;
+ varpd_panic_thread = thr_self();
+
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ (void) vsnprintf(varpd_panic_buf, sizeof (varpd_panic_buf), fmt,
+ ap);
+ }
+ abort();
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c
new file mode 100644
index 0000000000..27cc802a9c
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c
@@ -0,0 +1,586 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * varpd persistence backend
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <strings.h>
+#include <librename.h>
+#include <md5.h>
+#include <sys/sysmacros.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include <umem.h>
+#include <sys/debug.h>
+
+#include <libvarpd_impl.h>
+
+static uint8_t varpd_persist_magic[4] = {
+ 'v',
+ 'a',
+ 'r',
+ 'p',
+};
+
+#define VARPD_PERSIST_MAXWRITE 4096
+#define VARPD_PERSIST_VERSION_ONE 1
+#define VARPD_PERSIST_SUFFIX ".varpd"
+
+typedef struct varpd_persist_header {
+ uint8_t vph_magic[4];
+ uint32_t vph_version;
+ uint8_t vph_md5[16];
+} varpd_persist_header_t;
+
+void
+libvarpd_persist_init(varpd_impl_t *vip)
+{
+ vip->vdi_persistfd = -1;
+ if (rwlock_init(&vip->vdi_pfdlock, USYNC_THREAD, NULL) != 0)
+ libvarpd_panic("failed to create rw vdi_pfdlock");
+}
+
+void
+libvarpd_persist_fini(varpd_impl_t *vip)
+{
+ /*
+ * Clean up for someone that left something behind.
+ */
+ if (vip->vdi_persistfd != -1) {
+ if (close(vip->vdi_persistfd) != 0)
+ libvarpd_panic("failed to close persist fd %d: %d",
+ vip->vdi_persistfd, errno);
+ vip->vdi_persistfd = -1;
+ }
+ if (rwlock_destroy(&vip->vdi_pfdlock) != 0)
+ libvarpd_panic("failed to destroy rw vdi_pfdlock");
+}
+
+int
+libvarpd_persist_enable(varpd_handle_t *vhp, const char *rootdir)
+{
+ int fd;
+ struct stat st;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ fd = open(rootdir, O_RDONLY);
+ if (fd < 0)
+ return (errno);
+
+ if (fstat(fd, &st) != 0) {
+ int ret = errno;
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (ret);
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (EINVAL);
+ }
+
+
+ VERIFY0(rw_wrlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd != -1) {
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (EEXIST);
+ }
+ vip->vdi_persistfd = fd;
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+
+ return (0);
+}
+
+static int
+libvarpd_persist_write(int fd, const void *buf, size_t buflen)
+{
+ ssize_t ret;
+ off_t off = 0;
+
+ while (buflen > 0) {
+ ret = write(fd, (void *)((uintptr_t)buf + off),
+ MIN(buflen, VARPD_PERSIST_MAXWRITE));
+ if (ret == -1 && errno == EINTR)
+ continue;
+ if (ret == -1)
+ return (errno);
+
+ off += ret;
+ buflen -= ret;
+ }
+
+ return (0);
+}
+
+static int
+libvarpd_persist_nvlist(int dirfd, uint64_t id, nvlist_t *nvl)
+{
+ int err, fd;
+ size_t size;
+ varpd_persist_header_t hdr;
+ librename_atomic_t *lrap;
+ char *buf = NULL, *name;
+
+ if ((err = nvlist_pack(nvl, &buf, &size, NV_ENCODE_XDR, 0)) != 0)
+ return (err);
+
+ if (asprintf(&name, "%llu%s", (unsigned long long)id, ".varpd") == -1) {
+ err = errno;
+ free(buf);
+ return (err);
+ }
+
+ if ((err = librename_atomic_fdinit(dirfd, name, NULL, 0600, 0,
+ &lrap)) != 0) {
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ fd = librename_atomic_fd(lrap);
+
+ bzero(&hdr, sizeof (varpd_persist_header_t));
+ bcopy(varpd_persist_magic, hdr.vph_magic, sizeof (varpd_persist_magic));
+ hdr.vph_version = VARPD_PERSIST_VERSION_ONE;
+ md5_calc(hdr.vph_md5, buf, size);
+
+ if ((err = libvarpd_persist_write(fd, &hdr,
+ sizeof (varpd_persist_header_t))) != 0) {
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ if ((err = libvarpd_persist_write(fd, buf, size)) != 0) {
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ do {
+ err = librename_atomic_commit(lrap);
+ } while (err == EINTR);
+
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+}
+
+int
+libvarpd_persist_instance(varpd_impl_t *vip, varpd_instance_t *inst)
+{
+ int err = 0;
+ nvlist_t *nvl = NULL, *cvl = NULL;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ /* Check if persistence exists */
+ if (vip->vdi_persistfd == -1)
+ goto out;
+
+ if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto out;
+
+ if ((err = nvlist_alloc(&cvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint64(nvl, "vri_id", inst->vri_id)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint32(nvl, "vri_linkid", inst->vri_linkid)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint32(nvl, "vri_dest",
+ (uint32_t)inst->vri_dest)) != 0)
+ goto out;
+ if ((err = nvlist_add_uint32(nvl, "vri_mode",
+ (uint32_t)inst->vri_mode)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_string(nvl, "vri_plugin",
+ inst->vri_plugin->vpp_name)) != 0)
+ goto out;
+
+ err = inst->vri_plugin->vpp_ops->vpo_save(inst->vri_private, cvl);
+ if (err != 0)
+ goto out;
+
+ if ((err = nvlist_add_nvlist(nvl, "vri_private", cvl)) != 0)
+ goto out;
+
+ err = libvarpd_persist_nvlist(vip->vdi_persistfd, inst->vri_id, nvl);
+out:
+ nvlist_free(nvl);
+ nvlist_free(cvl);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (err);
+}
+
+void
+libvarpd_torch_instance(varpd_impl_t *vip, varpd_instance_t *inst)
+{
+ char buf[32];
+ int ret;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd == -1) {
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return;
+ }
+
+ if (snprintf(buf, sizeof (buf), "%lld.varpd", inst->vri_id) >= 32)
+ libvarpd_panic("somehow exceeded static value for "
+ "libvarpd_torch_instance buffer");
+
+ do {
+ ret = unlinkat(vip->vdi_persistfd, buf, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret != 0) {
+ switch (errno) {
+ case ENOENT:
+ break;
+ default:
+ libvarpd_panic("failed to unlinkat %d`%s: %s",
+ vip->vdi_persistfd, buf, strerror(errno));
+ }
+ }
+
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+}
+
+static int
+libvarpd_persist_restore_instance(varpd_impl_t *vip, nvlist_t *nvl)
+{
+ int err;
+ nvlist_t *pvl;
+ uint64_t id, flags, vid;
+ uint32_t linkid, dest, mode;
+ char *pluginstr;
+ varpd_plugin_t *plugin;
+ overlay_plugin_dest_t adest;
+ varpd_instance_t *inst, lookup;
+
+ if (nvlist_lookup_uint64(nvl, "vri_id", &id) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_linkid", &linkid) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_dest", &dest) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_mode", &mode) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_string(nvl, "vri_plugin", &pluginstr) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_nvlist(nvl, "vri_private", &pvl) != 0)
+ return (EINVAL);
+
+ plugin = libvarpd_plugin_lookup(vip, pluginstr);
+ if (plugin == NULL)
+ return (EINVAL);
+
+ if (plugin->vpp_mode != mode)
+ return (EINVAL);
+
+ if (libvarpd_overlay_info(vip, linkid, &adest, &flags, &vid) != 0)
+ return (EINVAL);
+
+ if (dest != adest)
+ return (EINVAL);
+
+ inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
+ if (inst == NULL)
+ libvarpd_panic("failed to allocate instance for restore");
+
+ inst->vri_id = id_alloc_specific(vip->vdi_idspace, id);
+ if (inst->vri_id != id) {
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (EINVAL);
+ }
+
+ inst->vri_linkid = linkid;
+ inst->vri_vnetid = vid;
+ inst->vri_mode = plugin->vpp_mode;
+ inst->vri_dest = dest;
+ inst->vri_plugin = plugin;
+ inst->vri_impl = vip;
+ inst->vri_flags = 0;
+ if (plugin->vpp_ops->vpo_restore(pvl, (varpd_provider_handle_t *)inst,
+ dest, &inst->vri_private) != 0) {
+ id_free(vip->vdi_idspace, id);
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (EINVAL);
+ }
+
+ if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create vri_lock mutex");
+
+ mutex_enter(&vip->vdi_lock);
+ lookup.vri_id = inst->vri_id;
+ if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate instance with id %d",
+ lookup.vri_id);
+ avl_add(&vip->vdi_instances, inst);
+ lookup.vri_linkid = inst->vri_linkid;
+ if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate linstance with id %d",
+ lookup.vri_linkid);
+ avl_add(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+
+ if (plugin->vpp_ops->vpo_start(inst->vri_private) != 0) {
+ libvarpd_instance_destroy((varpd_instance_handle_t *)inst);
+ return (EINVAL);
+ }
+
+ if (flags & OVERLAY_TARG_INFO_F_ACTIVE)
+ (void) libvarpd_overlay_disassociate(inst);
+
+ if (libvarpd_overlay_associate(inst) != 0) {
+ libvarpd_instance_destroy((varpd_instance_handle_t *)inst);
+ return (EINVAL);
+ }
+
+ if (flags & OVERLAY_TARG_INFO_F_DEGRADED) {
+ if ((err = libvarpd_overlay_restore(inst)) != 0) {
+ libvarpd_panic("failed to restore instance %p: %d\n",
+ inst, err);
+ }
+ }
+
+ mutex_enter(&inst->vri_lock);
+ inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
+ mutex_exit(&inst->vri_lock);
+
+ return (0);
+}
+
+static int
+libvarpd_persist_restore_one(varpd_impl_t *vip, int fd)
+{
+ int err;
+ size_t fsize;
+ struct stat st;
+ void *buf, *datap;
+ varpd_persist_header_t *hdr;
+ uint8_t md5[16];
+ nvlist_t *nvl;
+
+ if (fstat(fd, &st) != 0)
+ return (errno);
+
+ if (st.st_size <= sizeof (varpd_persist_header_t))
+ return (EINVAL);
+ fsize = st.st_size - sizeof (varpd_persist_header_t);
+
+ buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == MAP_FAILED)
+ return (errno);
+
+ hdr = buf;
+ if (bcmp(varpd_persist_magic, hdr->vph_magic,
+ sizeof (varpd_persist_magic)) != 0) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ if (hdr->vph_version != VARPD_PERSIST_VERSION_ONE) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ datap = (void *)((uintptr_t)buf + sizeof (varpd_persist_header_t));
+ md5_calc(md5, datap, fsize);
+ if (bcmp(md5, hdr->vph_md5, sizeof (uint8_t) * 16) != 0) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ err = nvlist_unpack(datap, fsize, &nvl, 0);
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+
+ if (err != 0)
+ return (EINVAL);
+
+ err = libvarpd_persist_restore_instance(vip, nvl);
+ nvlist_free(nvl);
+ return (err);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_check_degrade_cb(varpd_impl_t *vip, datalink_id_t linkid, void *arg)
+{
+ varpd_instance_t *inst;
+
+ mutex_enter(&vip->vdi_lock);
+ for (inst = avl_first(&vip->vdi_instances); inst != NULL;
+ inst = AVL_NEXT(&vip->vdi_instances, inst)) {
+ if (inst->vri_linkid == linkid) {
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+ }
+ }
+
+ mutex_exit(&vip->vdi_lock);
+
+ (void) libvarpd_overlay_degrade_datalink(vip, linkid,
+ "no varpd instance exists");
+ return (0);
+}
+
+static void
+libvarpd_check_degrade(varpd_impl_t *vip)
+{
+ (void) libvarpd_overlay_iter(vip, libvarpd_check_degrade_cb, NULL);
+}
+
+int
+libvarpd_persist_restore(varpd_handle_t *vhp)
+{
+ int dirfd;
+ int ret = 0;
+ DIR *dirp = NULL;
+ struct dirent *dp;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ if ((dirfd = dup(vip->vdi_persistfd)) < 0) {
+ ret = errno;
+ goto out;
+ }
+
+ if ((dirp = fdopendir(dirfd)) == NULL) {
+ ret = errno;
+ if (close(dirfd) != 0)
+ libvarpd_panic("failed to close dirfd %d: %d",
+ dirfd, errno);
+ goto out;
+ }
+
+ for (;;) {
+ int fd;
+ uint64_t id;
+ char *eptr;
+ struct stat st;
+
+ errno = 0;
+ dp = readdir(dirp);
+ if (dp == NULL) {
+ ret = errno;
+ break;
+ }
+
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ /*
+ * Leave files that we don't recognize alone. A valid file has
+ * the format `%llu.varpd`.
+ */
+ errno = 0;
+ id = strtoull(dp->d_name, &eptr, 10);
+ if ((id == 0 && errno == EINVAL) ||
+ (id == ULLONG_MAX && errno == ERANGE))
+ continue;
+
+ if (strcmp(eptr, VARPD_PERSIST_SUFFIX) != 0)
+ continue;
+
+ fd = openat(vip->vdi_persistfd, dp->d_name, O_RDONLY);
+ if (fd < 0) {
+ ret = errno;
+ break;
+ }
+
+ if (fstat(fd, &st) != 0) {
+ ret = errno;
+ break;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close fd (%s) %d: "
+ "%d\n", dp->d_name, fd, errno);
+ continue;
+ }
+
+ ret = libvarpd_persist_restore_one(vip, fd);
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close fd (%s) %d: "
+ "%d\n", dp->d_name, fd, errno);
+ /*
+ * This is an invalid file. We'll unlink it to save us this
+ * trouble in the future.
+ */
+ if (ret != 0) {
+ if (unlinkat(vip->vdi_persistfd, dp->d_name, 0) != 0) {
+ ret = errno;
+ break;
+ }
+ }
+ }
+
+ libvarpd_check_degrade(vip);
+
+out:
+ if (dirp != NULL)
+ (void) closedir(dirp);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (ret);
+}
+
+int
+libvarpd_persist_disable(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ VERIFY0(rw_wrlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd == -1) {
+ mutex_exit(&vip->vdi_lock);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (ENOENT);
+ }
+ if (close(vip->vdi_persistfd) != 0)
+ libvarpd_panic("failed to close persist fd %d: %d",
+ vip->vdi_persistfd, errno);
+ vip->vdi_persistfd = -1;
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (0);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c
new file mode 100644
index 0000000000..ac73286fdd
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c
@@ -0,0 +1,269 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd plugin management
+ */
+
+#include <libvarpd_impl.h>
+#include <errno.h>
+#include <umem.h>
+#include <assert.h>
+#include <strings.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+#include <bunyan.h>
+
+static varpd_impl_t *varpd_load_handle;
+static const char *varpd_load_path;
+static mutex_t varpd_load_lock;
+static cond_t varpd_load_cv;
+
+int
+libvarpd_plugin_comparator(const void *lp, const void *rp)
+{
+ int ret;
+ const varpd_plugin_t *lpp, *rpp;
+
+ lpp = lp;
+ rpp = rp;
+
+ ret = strcmp(lpp->vpp_name, rpp->vpp_name);
+ if (ret > 0)
+ return (1);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+varpd_plugin_register_t *
+libvarpd_plugin_alloc(uint_t version, int *errp)
+{
+ int err;
+ varpd_plugin_register_t *vprp;
+
+ if (errp == NULL)
+ errp = &err;
+
+ if (version != VARPD_VERSION_ONE) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "unsupported registration version",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_INT32, "module_version", version,
+ BUNYAN_T_END);
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ vprp = umem_alloc(sizeof (varpd_plugin_register_t), UMEM_DEFAULT);
+ if (vprp == NULL) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "failed to allocate registration handle",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_END);
+ *errp = ENOMEM;
+ return (NULL);
+ }
+
+ vprp->vpr_version = VARPD_VERSION_ONE;
+
+ return (vprp);
+}
+
+void
+libvarpd_plugin_free(varpd_plugin_register_t *vprp)
+{
+ umem_free(vprp, sizeof (varpd_plugin_register_t));
+}
+
+int
+libvarpd_plugin_register(varpd_plugin_register_t *vprp)
+{
+ varpd_plugin_t *vpp;
+ varpd_plugin_t lookup;
+
+ vpp = umem_alloc(sizeof (varpd_plugin_t), UMEM_DEFAULT);
+ if (vpp == NULL) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "failed to allocate memory for the varpd_plugin_t",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_END);
+ return (ENOMEM);
+ }
+
+ /* Watch out for an evil plugin */
+ if (vprp->vpr_version != VARPD_VERSION_ONE) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "unsupported registration version",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_INT32, "module_version", vprp->vpr_version,
+ BUNYAN_T_END);
+ return (EINVAL);
+ }
+
+ mutex_enter(&varpd_load_lock);
+ if (varpd_load_handle == NULL)
+ libvarpd_panic("varpd_load_handle was unexpectedly null");
+
+ mutex_enter(&varpd_load_handle->vdi_lock);
+ lookup.vpp_name = vprp->vpr_name;
+ if (avl_find(&varpd_load_handle->vdi_plugins, &lookup, NULL) != NULL) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "module already exists with requested name",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_STRING, "name", vprp->vpr_name,
+ BUNYAN_T_END);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+ umem_free(vpp, sizeof (varpd_plugin_t));
+ return (EEXIST);
+ }
+ vpp->vpp_name = strdup(vprp->vpr_name);
+ if (vpp->vpp_name == NULL) {
+ (void) bunyan_warn(varpd_load_handle->vdi_bunyan,
+ "failed to allocate memory to duplicate name",
+ BUNYAN_T_STRING, "module_path", varpd_load_path,
+ BUNYAN_T_END);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+ umem_free(vpp, sizeof (varpd_plugin_t));
+ return (ENOMEM);
+ }
+
+ vpp->vpp_mode = vprp->vpr_mode;
+ vpp->vpp_ops = vprp->vpr_ops;
+ if (mutex_init(&vpp->vpp_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create plugin's vpp_lock");
+ vpp->vpp_active = 0;
+ avl_add(&varpd_load_handle->vdi_plugins, vpp);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+
+ return (0);
+}
+
+varpd_plugin_t *
+libvarpd_plugin_lookup(varpd_impl_t *vip, const char *name)
+{
+ varpd_plugin_t lookup, *ret;
+
+ lookup.vpp_name = name;
+ mutex_enter(&vip->vdi_lock);
+ ret = avl_find(&vip->vdi_plugins, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_plugin_load_cb(varpd_impl_t *vip, const char *path, void *unused)
+{
+ void *dlp;
+
+ varpd_load_path = path;
+ dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW);
+ if (dlp == NULL) {
+ (void) bunyan_error(vip->vdi_bunyan, "dlopen failed",
+ BUNYAN_T_STRING, "module path", path,
+ BUNYAN_T_END);
+ }
+ path = NULL;
+
+ return (0);
+}
+
+int
+libvarpd_plugin_load(varpd_handle_t *vph, const char *path)
+{
+ int ret = 0;
+ varpd_impl_t *vip = (varpd_impl_t *)vph;
+
+ if (vip == NULL || path == NULL)
+ return (EINVAL);
+ mutex_enter(&varpd_load_lock);
+ while (varpd_load_handle != NULL)
+ (void) cond_wait(&varpd_load_cv, &varpd_load_lock);
+ varpd_load_handle = vip;
+ mutex_exit(&varpd_load_lock);
+
+ ret = libvarpd_dirwalk(vip, path, ".so", libvarpd_plugin_load_cb, NULL);
+
+ mutex_enter(&varpd_load_lock);
+ varpd_load_handle = NULL;
+ (void) cond_signal(&varpd_load_cv);
+ mutex_exit(&varpd_load_lock);
+
+ return (ret);
+}
+
+int
+libvarpd_plugin_walk(varpd_handle_t *vph, libvarpd_plugin_walk_f func,
+ void *arg)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vph;
+ varpd_plugin_t *vpp;
+
+ mutex_enter(&vip->vdi_lock);
+ for (vpp = avl_first(&vip->vdi_plugins); vpp != NULL;
+ vpp = AVL_NEXT(&vip->vdi_plugins, vpp)) {
+ if (func(vph, vpp->vpp_name, arg) != 0) {
+ mutex_exit(&vip->vdi_lock);
+ return (1);
+ }
+ }
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+}
+
+void
+libvarpd_plugin_init(void)
+{
+ if (mutex_init(&varpd_load_lock, USYNC_THREAD | LOCK_RECURSIVE |
+ LOCK_ERRORCHECK, NULL) != 0)
+ libvarpd_panic("failed to create varpd_load_lock");
+
+ if (cond_init(&varpd_load_cv, USYNC_THREAD, NULL) != 0)
+ libvarpd_panic("failed to create varpd_load_cv");
+
+ varpd_load_handle = NULL;
+}
+
+void
+libvarpd_plugin_fini(void)
+{
+ assert(varpd_load_handle == NULL);
+ if (mutex_destroy(&varpd_load_lock) != 0)
+ libvarpd_panic("failed to destroy varpd_load_lock");
+ if (cond_destroy(&varpd_load_cv) != 0)
+ libvarpd_panic("failed to destroy varpd_load_cv");
+}
+
+void
+libvarpd_plugin_prefork(void)
+{
+ mutex_enter(&varpd_load_lock);
+ while (varpd_load_handle != NULL)
+ (void) cond_wait(&varpd_load_cv, &varpd_load_lock);
+}
+
+void
+libvarpd_plugin_postfork(void)
+{
+ (void) cond_signal(&varpd_load_cv);
+ mutex_exit(&varpd_load_lock);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c
new file mode 100644
index 0000000000..abe65a8c5d
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c
@@ -0,0 +1,299 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd property management
+ */
+
+#include <libvarpd_impl.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/mac.h>
+#include <umem.h>
+
+typedef struct varpd_prop_info {
+ varpd_impl_t *vprop_vip;
+ varpd_instance_t *vprop_instance;
+ uint_t vprop_type;
+ uint_t vprop_prot;
+ uint32_t vprop_defsize;
+ uint32_t vprop_psize;
+ char vprop_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vprop_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vprop_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_prop_info_t;
+
+/* Internal Properties */
+static int varpd_nintprops = 1;
+static const char *varpd_intprops[] = {
+ "search"
+};
+
+static int
+libvarpd_prop_get_search(varpd_prop_info_t *infop, void *buf, uint32_t *sizep)
+{
+ varpd_plugin_t *vpp = infop->vprop_instance->vri_plugin;
+ size_t nlen;
+
+ nlen = strlen(vpp->vpp_name) + 1;
+ if (nlen > *sizep)
+ return (EOVERFLOW);
+ *sizep = nlen;
+ (void) strlcpy(buf, vpp->vpp_name, *sizep);
+ return (0);
+}
+
+void
+libvarpd_prop_set_name(varpd_prop_handle_t *phdl, const char *name)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ (void) strlcpy(infop->vprop_name, name, OVERLAY_PROP_NAMELEN);
+}
+
+void
+libvarpd_prop_set_prot(varpd_prop_handle_t *phdl, overlay_prop_prot_t perm)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ infop->vprop_prot = perm;
+}
+
+void
+libvarpd_prop_set_type(varpd_prop_handle_t *phdl, overlay_prop_type_t type)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ infop->vprop_type = type;
+}
+
+int
+libvarpd_prop_set_default(varpd_prop_handle_t *phdl, void *buf, ssize_t len)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+
+ if (len > LIBVARPD_PROP_SIZEMAX)
+ return (E2BIG);
+
+ if (len < 0)
+ return (EOVERFLOW);
+
+ bcopy(buf, infop->vprop_default, len);
+ infop->vprop_defsize = len;
+ return (0);
+}
+
+void
+libvarpd_prop_set_nodefault(varpd_prop_handle_t *phdl)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+
+ infop->vprop_default[0] = '\0';
+ infop->vprop_defsize = 0;
+}
+
+void
+libvarpd_prop_set_range_uint32(varpd_prop_handle_t *phdl, uint32_t min,
+ uint32_t max)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_UINT32)
+ return;
+
+ if (infop->vprop_psize + sizeof (mac_propval_uint32_range_t) >
+ sizeof (infop->vprop_poss))
+ return;
+
+ infop->vprop_psize += sizeof (mac_propval_uint32_range_t);
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_UINT32;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_min = min;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_max = max;
+}
+
+void
+libvarpd_prop_set_range_str(varpd_prop_handle_t *phdl, const char *str)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ size_t len = strlen(str) + 1; /* Account for a null terminator */
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+ mac_propval_str_range_t *pstr = &rangep->u.mpr_str;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_STR)
+ return;
+
+ if (infop->vprop_psize + len > sizeof (infop->vprop_poss))
+ return;
+
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_STR;
+ (void) strlcpy((char *)&pstr->mpur_data[pstr->mpur_nextbyte], str,
+ sizeof (infop->vprop_poss) - infop->vprop_psize);
+ pstr->mpur_nextbyte += len;
+ infop->vprop_psize += len;
+}
+
+int
+libvarpd_prop_handle_alloc(varpd_handle_t *vph, varpd_instance_handle_t *inst,
+ varpd_prop_handle_t **phdlp)
+{
+ varpd_prop_info_t *infop;
+
+ infop = umem_alloc(sizeof (varpd_prop_info_t), UMEM_DEFAULT);
+ if (infop == NULL)
+ return (ENOMEM);
+
+ bzero(infop, sizeof (varpd_prop_info_t));
+ infop->vprop_vip = (varpd_impl_t *)vph;
+ infop->vprop_instance = (varpd_instance_t *)inst;
+
+ *phdlp = (varpd_prop_handle_t *)infop;
+ return (0);
+}
+
+void
+libvarpd_prop_handle_free(varpd_prop_handle_t *phdl)
+{
+ umem_free(phdl, sizeof (varpd_prop_info_t));
+}
+
+int
+libvarpd_prop_nprops(varpd_instance_handle_t *ihdl, uint_t *np)
+{
+ int ret;
+ varpd_instance_t *instp = (varpd_instance_t *)ihdl;
+
+ ret = instp->vri_plugin->vpp_ops->vpo_nprops(instp->vri_private, np);
+ if (ret != 0)
+ return (ret);
+ *np += varpd_nintprops;
+ return (0);
+}
+
+static int
+libvarpd_prop_info_fill_int_cb(varpd_handle_t *handle, const char *name,
+ void *arg)
+{
+ varpd_prop_handle_t *vph = arg;
+ libvarpd_prop_set_range_str(vph, name);
+ return (0);
+}
+
+static int
+libvarpd_prop_info_fill_int(varpd_prop_handle_t *vph, uint_t propid)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)vph;
+ if (propid >= varpd_nintprops)
+ abort();
+ libvarpd_prop_set_name(vph, varpd_intprops[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_READ);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
+ libvarpd_prop_set_nodefault(vph);
+ libvarpd_plugin_walk((varpd_handle_t *)infop->vprop_instance->vri_impl,
+ libvarpd_prop_info_fill_int_cb, vph);
+ return (0);
+}
+
+int
+libvarpd_prop_info_fill(varpd_prop_handle_t *phdl, uint_t propid)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+
+ infop->vprop_psize = sizeof (mac_propval_range_t);
+
+ bzero(rangep, sizeof (mac_propval_range_t));
+ if (propid < varpd_nintprops) {
+ return (libvarpd_prop_info_fill_int(phdl, propid));
+ } else {
+ varpd_plugin_t *vpp = instp->vri_plugin;
+ return (vpp->vpp_ops->vpo_propinfo(instp->vri_private,
+ propid - varpd_nintprops, phdl));
+ }
+}
+
+int
+libvarpd_prop_info(varpd_prop_handle_t *phdl, const char **namep,
+ uint_t *typep, uint_t *protp, const void **defp, uint32_t *sizep,
+ const mac_propval_range_t **possp)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ if (namep != NULL)
+ *namep = infop->vprop_name;
+ if (typep != NULL)
+ *typep = infop->vprop_type;
+ if (protp != NULL)
+ *protp = infop->vprop_prot;
+ if (defp != NULL)
+ *defp = infop->vprop_default;
+ if (sizep != NULL)
+ *sizep = infop->vprop_psize;
+ if (possp != NULL)
+ *possp = (mac_propval_range_t *)infop->vprop_poss;
+ return (0);
+}
+
+int
+libvarpd_prop_get(varpd_prop_handle_t *phdl, void *buf, uint32_t *sizep)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+
+ if (infop->vprop_name[0] == '\0')
+ return (EINVAL);
+
+ if (strcmp(varpd_intprops[0], infop->vprop_name) == 0) {
+ /* search property */
+ return (libvarpd_prop_get_search(infop, buf, sizep));
+ }
+
+ return (instp->vri_plugin->vpp_ops->vpo_getprop(instp->vri_private,
+ infop->vprop_name, buf, sizep));
+}
+
+int
+libvarpd_prop_set(varpd_prop_handle_t *phdl, const void *buf, uint32_t size)
+{
+ int i;
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+
+ if (infop->vprop_name[0] == '\0')
+ return (EINVAL);
+
+ for (i = 0; i < varpd_nintprops; i++) {
+ if (strcmp(infop->vprop_name, varpd_intprops[i]) == 0) {
+ return (EPERM);
+ }
+ }
+
+ return (instp->vri_plugin->vpp_ops->vpo_setprop(instp->vri_private,
+ infop->vprop_name, buf, size));
+}
+
+void
+libvarpd_prop_door_convert(const varpd_prop_handle_t *phdl,
+ varpd_client_propinfo_arg_t *vcfap)
+{
+ const varpd_prop_info_t *infop = (const varpd_prop_info_t *)phdl;
+
+ vcfap->vcfa_type = infop->vprop_type;
+ vcfap->vcfa_prot = infop->vprop_prot;
+ vcfap->vcfa_defsize = infop->vprop_defsize;
+ vcfap->vcfa_psize = infop->vprop_psize;
+ bcopy(infop->vprop_name, vcfap->vcfa_name, LIBVARPD_PROP_NAMELEN);
+ bcopy(infop->vprop_default, vcfap->vcfa_default, LIBVARPD_PROP_SIZEMAX);
+ bcopy(infop->vprop_poss, vcfap->vcfa_poss, LIBVARPD_PROP_SIZEMAX);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h
new file mode 100644
index 0000000000..64fa99d308
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h
@@ -0,0 +1,419 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_PROVIDER_H
+#define _LIBVARPD_PROVIDER_H
+
+/*
+ * varpd provider interface for lookup modules
+ *
+ * This header file defines all the structures and functions that a given lookup
+ * module needs to implement and perform its purpose. At this time, all of these
+ * interfaces are considered private to illumos and therefore are subject to
+ * change. At some point we will move to more broadly stabilize these interfaces
+ * and commit to them. Until such time, expect breakage for out of gate
+ * consumers.
+ *
+ * A plugin is a dynamic shared object that is placed inside of varpd's default
+ * module.
+ *
+ * The shared object must define an initializer, such as with #pragma init. This
+ * function will be run with the module is dlopened by libvarpd. In that init
+ * function, the function must allocate a varpd_plugin_register by calling
+ * libvarpd_plugin_alloc() and specifying VARPD_CURRENT_VERSION. If that
+ * succeeds, then it should proceed to fill out the registration and then call,
+ * libvarpd_plugin_register() with it. Regardless of whether it succeeds or
+ * fails, it should call libvarpd_plugin_free(). In the case of failure, there
+ * is not much that the module should do, other than log some message to the
+ * standard bunyan logger that exists.
+ *
+ * Once libvarpd_plugin_register() returns, the module should assume that any
+ * of the operations it defined in the operation vector may be called and
+ * therefore it is recommended that any other required initialization should be
+ * performed at that time.
+ *
+ * At this time, once a plugin is loaded, it will not be unloaded. Therefore,
+ * there is no corresponding requirement to unregister, though that may come in
+ * a future version.
+ *
+ * -----------------------------
+ * Plugin Types and Destinations
+ * -----------------------------
+ *
+ * There are two different kinds of plugins in this world, there are point to
+ * point plugins and there are dynamic plugins. The key difference is in how
+ * packets are routed through the system. In a point to point plugin, a single
+ * destination is used when the instance is started. In dynamic plugins,
+ * destinations are looked up as they are required and an instance of a plugin
+ * is required to provide that.
+ *
+ * These point to point plugins define a type of OVERLAY_TARGET_POINT and the
+ * dynamic plugins instead define a type of OVERLAY_TARGET_DYNAMIC.
+ *
+ * Encapsulation plugins have multiple types of destinations. They may require
+ * an Ethernet address (OVERLAY_PLUGIN_D_ETHERNET), IP address
+ * (OVERLAY_PLUGIN_D_IP), and a port (OVERLAY_PLUGIN_D_PORT). For example,
+ * consider vxlan, it requires an IP and a port; while a hypothetical nvgre,
+ * would only require an IP.
+ *
+ * A plugin is allowed to describe which of these fields that it supports and
+ * given which encapsulation plugin it is paired with, it can support a varying
+ * degree of properties. For example, consider the example of the direct plugin.
+ * It has a notion of a destination port and a destination IP. If it is paired
+ * with a plugin that only requires an IP, then it wouldn't need to show a
+ * property that's related to a destination port.
+ *
+ * ------------------
+ * Plugin Definitions
+ * ------------------
+ *
+ * A plugin is required to fill in both an operations vector and a series of
+ * additional metadata that it passed in to libvarpd_plugin_register(). The
+ * following lists all of the routines and their purposes. The full signatures
+ * are available in the body of the header file.
+ *
+ * varpd_plugin_create_f
+ *
+ * Create a new instance of a plugin. Each instance refers to a different
+ * overlay device and thus a different overlay identifier. Each instance
+ * has its own property space and is unique. This function gives the chance
+ * for the plugin to create and provide any private data that it will
+ * require.
+ *
+ * In addition, the plugin is given the type of destination that is
+ * required and it is its job to determine whether or not it supports it.
+ *
+ * varpd_plugin_destory_f
+ *
+ * This is the opposite of varpd_plugin_create_f. It is called to allow the
+ * plugin to reclaim any resources with the private argument that it passed
+ * out as part of the destroy function.
+ *
+ * varpd_plugin_start_f
+ *
+ * This routine is called to indicate that an instance should be started.
+ * This is a plugin's chance to verify that it has all of its required
+ * properties set and to take care of any action that needs to be handled
+ * to begin the plugin. After this point it will be legal to have the
+ * varpd_plugin_default_f, varpd_plugin_lookup_f, varpd_plugin_arp_f and
+ * varpd_plugin_dhcp_f endpoints called.
+ *
+ * varpd_plugin_stop_f
+ *
+ * This routine is called to indicate that an instance is stopping, it is
+ * the opposite of varpd_plugin_start_f. This is a chance to clean up
+ * resources that are a side effect of having started the instance.
+ *
+ * varpd_plugin_default_f
+ *
+ * This routine is defined by plugins of type OVERLAY_TARGET_POINT. It is
+ * used to answer the question of where should all traffic for this
+ * instance be destined. Plugins of type OVERLAY_TARGET_DYNAMIC should
+ * leave this entry set to NULL.
+ *
+ * On success, the default routine should return VARPD_LOOKUP_OK. On
+ * failure, it should return the macro VARPD_LOOKUP_DROP.
+ *
+ * varpd_plugin_lookup_f
+ *
+ * This routine must be defined by plugins of type OVERLAY_TARGET_DYNAMIC.
+ * It is used to lookup the destination for a given request. Each request
+ * comes in with its own MAC address this allows a plugin to direct it to
+ * any remote location.
+ *
+ * This is designed as an asynchronous API. Once a lookup is completed it
+ * should call libvarpd_plugin_query_reply() and pass as the second
+ * argument either VARPD_LOOKUP_OK to indicate that it went alright or it
+ * should reply VARPD_LOOKUP_DROP to indicate that the packet should be
+ * dropped.
+ *
+ * In addition, there are several utility routines that can take care of
+ * various kinds of traffic automatically. For example, if an ARP, NDP, or
+ * DHCP packet comes in, there are utilities such as
+ * libvarpd_plugin_proxy_arp(), libvarpd_plugin_proxy_ndp() and
+ * libvarpd_plugin_proxy_dhcp(), which allows the system to do the heavy
+ * lifting of validating the packet once it finds that it matches certain
+ * properties.
+ *
+ * varpd_plugin_arp_f
+ *
+ * This is an optional entry for plugins of type OVERLAY_TARGET_DYNAMIC.
+ * This is called after a plugin calls libvarpd_plugin_proxy_arp() and is
+ * used to ask the plugin to perform an ARP or NDP query. The type of query
+ * is passed in in the third argument, the only valid value for which will
+ * be VARPD_QTYPE_ETHERNET, to indicate we're doing an Ethernet lookup.
+ *
+ * The layer three IP address that is being looked up will be included in
+ * the struct sockaddr. The sockaddr(3SOCKET)'s sa_family will be set to
+ * indicate the type, eg. AF_INET or AF_INET6 and that will indicate the
+ * kind of sockaddr that will be used. For more information see
+ * sockaddr(3SOCKET). The implementation ensures that enough space for the
+ * link layer address will exist.
+ *
+ * This is an asynchronous lookup. Once the answer has been written, a
+ * plugin should call libvarpd_plugin_arp_reply and if it was successful,
+ * VARPD_LOOKUP_OK should be passed in and if it failed, VARPD_LOOKUP_DROP
+ * should be passed in instead.
+ *
+ * varpd_plugin_dhcp_f
+ *
+ * This is an optional entry for plugins of type OVERLAY_TARGET_DYNAMIC.
+ * This is called after a plugin calls the libvarpd_plugin_proxy_dhcp() and
+ * is used to ask the plugin to determine where is the DHCP server that
+ * this packet should actually be sent to. What is happening here is that
+ * rather than broadcast the initial DHCP request, we instead unicast it to
+ * a specified DHCP server that this operation vector indicates.
+ *
+ * The plugin is given a type, the same as the ARP plugin which indicates
+ * the kind of link layer address, the only valid type is
+ * VARPD_QTYPE_ETHERNET, other types should be rejected. Then, like the arp
+ * entry point, the dhcp entry point should determine the link layer
+ * address of the DHCP server and write that out in the appropriate memory
+ * and call libvarpd_plugin_dhcp_reply() when done. Similar to the arp
+ * entry point, it should use VARPD_LOOKUP_OK to indicate that it was
+ * filled in and VARPD_LOOKUP_DROP to indicate that it was not.
+ *
+ * varpd_plugin_nprops_f
+ *
+ * This is used by a plugin to indicate the number of properties that
+ * should exist for this instance. Recall from the section that Plugin
+ * types and Destinations, that the number of entries here may vary. As
+ * such, the plugin should return the number that is appropriate for the
+ * instance.
+ *
+ * This number will be used to obtain information about a property via the
+ * propinfo functions. However, the getprop and setprop interfaces will
+ * always use names to indicate the property it is getting and setting.
+ * This difference is structured this way to deal with property discovery
+ * and to make the getprop and setprop interfaces slightly easier for other
+ * parts of the broader varpd/dladm infrastructure.
+ *
+ * varpd_plugin_propinfo_f
+ *
+ * This interface is used to get information about a property, the property
+ * that information is being requested for is being passed in via the
+ * second argument. Here, callers should set properties such as the name,
+ * the protection, whether or not the property is required, set any default
+ * value, if it exist, and if relevant, set the valid range of values.
+ *
+ * varpd_plugin_getprop_f
+ *
+ * This is used to get the value of a property, if it is set. The passed in
+ * length indicates the length of the buffer that is used for updating
+ * properties. If it is not of sufficient size, the function should return
+ * an error and not update the buffer. Otherwise, it should update the size
+ * pointer with the valid size.
+ *
+ * varpd_plugin_setprop_f
+ *
+ * This is used to set the value of a property. An endpoint should validate
+ * that the property is valid before updating it. In addition, it should
+ * update its state as appropriate.
+ *
+ * varpd_plugin_save_f
+ *
+ * This is used to serialize the state of a given instance of a plugin such
+ * that if varpd crashes, it can be recovered. The plugin should write all
+ * state into the nvlist that it is passed in, it may use any keys and
+ * values that it wants. The only consumer of that nvlist will be the
+ * plugin itself when the restore endpoint is called.
+ *
+ * varpd_plugin_restore_f
+ *
+ * This is called by the server to restore an instance that used to exist,
+ * but was lost due to a crash. This is a combination of calling create and
+ * setting properties. The plugin should restore any private state that it
+ * can find recorded from the nvlist. The only items in the nvlist will be
+ * those that were written out during a previous call to
+ * varpd_plugin_save_f.
+ *
+ *
+ * Once all of these interfaces are implemented, the plugin should define the
+ * following members in the varpd_plugin_register_t.
+ *
+ * vpr_version
+ *
+ * This indicates the version of the plugin. Plugins should set this to the
+ * macro VARPD_CURRENT_VERSION.
+ *
+ * vpr_mode
+ *
+ * This indicates the mode of the plugin. The plugin's mode should be one
+ * of OVERLAY_TARGET_POINT and OVERLAY_TARGET_DYNAMIC. For more discussion
+ * of these types and the differences, see the section on Plugin Types and
+ * Destinations.
+ *
+ * vpr_name
+ *
+ * This is the name of the plugin. This is how users will refer to it in
+ * the context of running dladm(1M) commands. Note, this name must be
+ * unique across the different plugins, as it will cause others with the
+ * same name not to be registered.
+ *
+ * vpr_ops
+ *
+ * This is the operations vector as described above. Importantly, the
+ * member vpo_callbacks must be set to zero, this is being used for future
+ * expansion of the structure.
+ *
+ *
+ * --------------------------------------------------
+ * Downcalls, Upcalls, and Synchronization Guarantees
+ * --------------------------------------------------
+ *
+ * Every instance of a plugin is independent. Calls into a plugin may be made
+ * for different instances in parallel. Any necessary locking is left to the
+ * plugin module. Within an instance, various calls may come in parallel.
+ *
+ * The primary guarantees are that none of the varpd_plugin_save_f,
+ * varpd_plugin_lookup_f, varpd_default_f, varpd_plugin_arp_f, and
+ * varpd_plugin_dhcp_f will be called until after a call to varpd_plugin_start_f
+ * has been called. Similarly, they will not be called after a call to
+ * vardp_plugin_stop_f.
+ *
+ * The functions documented in this header may be called back into from any
+ * context, including from the operation vectors.
+ */
+
+#include <bunyan.h>
+#include <libvarpd.h>
+#include <libnvpair.h>
+#include <sys/socket.h>
+#include <sys/overlay_target.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VARPD_VERSION_ONE 1
+#define VARPD_CURRENT_VERSION VARPD_VERSION_ONE
+
+typedef struct __varpd_provier_handle varpd_provider_handle_t;
+typedef struct __varpd_query_handle varpd_query_handle_t;
+typedef struct __varpd_arp_handle varpd_arp_handle_t;
+typedef struct __varpd_dhcp_handle varpd_dhcp_handle_t;
+
+typedef int (*varpd_plugin_create_f)(varpd_provider_handle_t *, void **,
+ overlay_plugin_dest_t);
+typedef int (*varpd_plugin_start_f)(void *);
+typedef void (*varpd_plugin_stop_f)(void *);
+typedef void (*varpd_plugin_destroy_f)(void *);
+
+#define VARPD_LOOKUP_OK (0)
+#define VARPD_LOOKUP_DROP (-1)
+typedef int (*varpd_plugin_default_f)(void *, overlay_target_point_t *);
+typedef void (*varpd_plugin_lookup_f)(void *, varpd_query_handle_t *,
+ const overlay_targ_lookup_t *, overlay_target_point_t *);
+
+#define VARPD_QTYPE_ETHERNET 0x0
+typedef void (*varpd_plugin_arp_f)(void *, varpd_arp_handle_t *, int,
+ const struct sockaddr *, uint8_t *);
+typedef void (*varpd_plugin_dhcp_f)(void *, varpd_dhcp_handle_t *, int,
+ const overlay_targ_lookup_t *, uint8_t *);
+
+typedef int (*varpd_plugin_nprops_f)(void *, uint_t *);
+typedef int (*varpd_plugin_propinfo_f)(void *, const uint_t,
+ varpd_prop_handle_t *);
+typedef int (*varpd_plugin_getprop_f)(void *, const char *, void *, uint32_t *);
+typedef int (*varpd_plugin_setprop_f)(void *, const char *, const void *,
+ const uint32_t);
+
+typedef int (*varpd_plugin_save_f)(void *, nvlist_t *);
+typedef int (*varpd_plugin_restore_f)(nvlist_t *, varpd_provider_handle_t *,
+ overlay_plugin_dest_t, void **);
+
+typedef struct varpd_plugin_ops {
+ uint_t vpo_callbacks;
+ varpd_plugin_create_f vpo_create;
+ varpd_plugin_start_f vpo_start;
+ varpd_plugin_stop_f vpo_stop;
+ varpd_plugin_destroy_f vpo_destroy;
+ varpd_plugin_default_f vpo_default;
+ varpd_plugin_lookup_f vpo_lookup;
+ varpd_plugin_nprops_f vpo_nprops;
+ varpd_plugin_propinfo_f vpo_propinfo;
+ varpd_plugin_getprop_f vpo_getprop;
+ varpd_plugin_setprop_f vpo_setprop;
+ varpd_plugin_save_f vpo_save;
+ varpd_plugin_restore_f vpo_restore;
+ varpd_plugin_arp_f vpo_arp;
+ varpd_plugin_dhcp_f vpo_dhcp;
+} varpd_plugin_ops_t;
+
+typedef struct varpd_plugin_register {
+ uint_t vpr_version;
+ uint_t vpr_mode;
+ const char *vpr_name;
+ const varpd_plugin_ops_t *vpr_ops;
+} varpd_plugin_register_t;
+
+extern varpd_plugin_register_t *libvarpd_plugin_alloc(uint_t, int *);
+extern void libvarpd_plugin_free(varpd_plugin_register_t *);
+extern int libvarpd_plugin_register(varpd_plugin_register_t *);
+
+/*
+ * Blowing up and logging
+ */
+extern void libvarpd_panic(const char *, ...) __NORETURN;
+extern const bunyan_logger_t *libvarpd_plugin_bunyan(varpd_provider_handle_t *);
+
+/*
+ * Misc. Information APIs
+ */
+extern uint64_t libvarpd_plugin_vnetid(varpd_provider_handle_t *);
+
+/*
+ * Lookup Replying query and proxying
+ */
+extern void libvarpd_plugin_query_reply(varpd_query_handle_t *, int);
+
+extern void libvarpd_plugin_proxy_arp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_proxy_ndp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_arp_reply(varpd_arp_handle_t *, int);
+
+extern void libvarpd_plugin_proxy_dhcp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_dhcp_reply(varpd_dhcp_handle_t *, int);
+
+
+/*
+ * Property information callbacks
+ */
+extern void libvarpd_prop_set_name(varpd_prop_handle_t *, const char *);
+extern void libvarpd_prop_set_prot(varpd_prop_handle_t *, overlay_prop_prot_t);
+extern void libvarpd_prop_set_type(varpd_prop_handle_t *, overlay_prop_type_t);
+extern int libvarpd_prop_set_default(varpd_prop_handle_t *, void *, ssize_t);
+extern void libvarpd_prop_set_nodefault(varpd_prop_handle_t *);
+extern void libvarpd_prop_set_range_uint32(varpd_prop_handle_t *, uint32_t,
+ uint32_t);
+extern void libvarpd_prop_set_range_str(varpd_prop_handle_t *, const char *);
+
+/*
+ * Various injecting and invalidation routines
+ */
+extern void libvarpd_inject_varp(varpd_provider_handle_t *, const uint8_t *,
+ const overlay_target_point_t *);
+extern void libvarpd_inject_arp(varpd_provider_handle_t *, const uint16_t,
+ const uint8_t *, const struct in_addr *, const uint8_t *);
+extern void libvarpd_fma_degrade(varpd_provider_handle_t *, const char *);
+extern void libvarpd_fma_restore(varpd_provider_handle_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_PROVIDER_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c
new file mode 100644
index 0000000000..e21fed2126
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c
@@ -0,0 +1,97 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <libvarpd_impl.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *
+libvarpd_isaext(void)
+{
+#if defined(__sparc)
+#if defined(__sparcv9)
+ return ("64");
+#else /* __sparcv9 */
+ return ("");
+#endif /* __sparvc9 */
+#elif defined(__amd64)
+ return ("64");
+#elif defined(__i386)
+ return ("");
+#else
+#error "unkonwn ISA"
+#endif
+}
+
+int
+libvarpd_dirwalk(varpd_impl_t *vip, const char *path, const char *suffix,
+ libvarpd_dirwalk_f func, void *arg)
+{
+ int ret;
+ size_t slen;
+ char *dirpath, *filepath;
+ DIR *dirp;
+ struct dirent *dp;
+ assert(vip != NULL && path != NULL);
+
+ if (asprintf(&dirpath, "%s/%s", path, libvarpd_isaext()) == -1)
+ return (errno);
+
+ if ((dirp = opendir(dirpath)) == NULL) {
+ ret = errno;
+ return (ret);
+ }
+
+ slen = strlen(suffix);
+ for (;;) {
+ size_t len;
+
+ errno = 0;
+ dp = readdir(dirp);
+ if (dp == NULL) {
+ ret = errno;
+ break;
+ }
+
+ len = strlen(dp->d_name);
+ if (len <= slen)
+ continue;
+
+ if (strcmp(suffix, dp->d_name + (len - slen)) != 0)
+ continue;
+
+ if (asprintf(&filepath, "%s/%s", dirpath, dp->d_name) == -1) {
+ ret = errno;
+ break;
+ }
+
+ if (func(vip, filepath, arg) != 0) {
+ free(filepath);
+ ret = 0;
+ break;
+ }
+
+ free(filepath);
+ }
+
+ (void) closedir(dirp);
+ free(dirpath);
+ return (ret);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/llib-lvarpd b/usr/src/lib/varpd/libvarpd/common/llib-lvarpd
new file mode 100644
index 0000000000..85150d3463
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/llib-lvarpd
@@ -0,0 +1,19 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <libvarpd.h>
diff --git a/usr/src/lib/varpd/libvarpd/common/mapfile-plugin b/usr/src/lib/varpd/libvarpd/common/mapfile-plugin
new file mode 100644
index 0000000000..8cef7f669f
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/mapfile-plugin
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_SCOPE {
+ global:
+ libvarpd_fma_degrade { FLAGS = EXTERN };
+ libvarpd_inject_arp { FLAGS = EXTERN };
+ libvarpd_inject_ndp { FLAGS = EXTERN };
+ libvarpd_inject_varp { FLAGS = EXTERN };
+ libvarpd_fma_restore { FLAGS = EXTERN };
+ libvarpd_panic { FLAGS = EXTERN };
+ libvarpd_plugin_alloc { FLAGS = EXTERN };
+ libvarpd_plugin_arp_reply { FLAGS = EXTERN };
+ libvarpd_plugin_dhcp_reply { FLAGS = EXTERN };
+ libvarpd_plugin_free { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_arp { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_dhcp { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_ndp { FLAGS = EXTERN };
+ libvarpd_plugin_query_reply { FLAGS = EXTERN };
+ libvarpd_plugin_register { FLAGS = EXTERN };
+ libvarpd_plugin_vnetid { FLAGS = EXTERN };
+ libvarpd_prop_set_name { FLAGS = EXTERN };
+ libvarpd_prop_set_prot { FLAGS = EXTERN };
+ libvarpd_prop_set_type { FLAGS = EXTERN };
+ libvarpd_prop_set_default { FLAGS = EXTERN };
+ libvarpd_prop_set_nodefault { FLAGS = EXTERN };
+ libvarpd_prop_set_range_uint32 { FLAGS = EXTERN };
+ libvarpd_prop_set_rangestr { FLAGS = EXTERN };
+};
diff --git a/usr/src/lib/varpd/libvarpd/common/mapfile-vers b/usr/src/lib/varpd/libvarpd/common/mapfile-vers
new file mode 100644
index 0000000000..7aa930cb54
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/mapfile-vers
@@ -0,0 +1,113 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ libvarpd_c_create;
+ libvarpd_c_destroy;
+ libvarpd_c_instance_activate;
+ libvarpd_c_instance_create;
+ libvarpd_c_instance_destroy;
+ libvarpd_c_prop_nprops;
+ libvarpd_c_prop_handle_alloc;
+ libvarpd_c_prop_handle_free;
+ libvarpd_c_prop_info_fill;
+ libvarpd_c_prop_info_fill_by_name;
+ libvarpd_c_prop_info;
+ libvarpd_c_prop_get;
+ libvarpd_c_prop_set;
+
+ libvarpd_c_instance_lookup;
+ libvarpd_c_instance_target_mode;
+ libvarpd_c_instance_cache_flush;
+ libvarpd_c_instance_cache_delete;
+ libvarpd_c_instance_cache_get;
+ libvarpd_c_instance_cache_set;
+ libvarpd_c_instance_cache_walk;
+
+ libvarpd_create;
+ libvarpd_destroy;
+
+ libvarpd_door_server_create;
+ libvarpd_door_server_destroy;
+
+ libvarpd_fma_degrade;
+ libvarpd_fma_restore;
+
+ libvarpd_inject_varp;
+ libvarpd_inject_arp;
+
+ libvarpd_instance_activate;
+ libvarpd_instance_create;
+ libvarpd_instance_destroy;
+ libvarpd_instance_lookup;
+ libvarpd_instance_id;
+
+ libvarpd_panic;
+
+ libvarpd_persist_disable;
+ libvarpd_persist_enable;
+ libvarpd_persist_restore;
+
+ libvarpd_plugin_alloc;
+ libvarpd_plugin_load;
+ libvarpd_plugin_free;
+ libvarpd_plugin_arp_reply;
+ libvarpd_plugin_dhcp_reply;
+ libvarpd_plugin_query_reply;
+ libvarpd_plugin_proxy_arp;
+ libvarpd_plugin_proxy_dhcp;
+ libvarpd_plugin_proxy_ndp;
+ libvarpd_plugin_register;
+ libvarpd_plugin_walk;
+ libvarpd_plugin_vnetid;
+
+ libvarpd_prop_set_default;
+ libvarpd_prop_set_nodefault;
+ libvarpd_prop_set_name;
+ libvarpd_prop_set_prot;
+ libvarpd_prop_set_range_uint32;
+ libvarpd_prop_set_range_str;
+ libvarpd_prop_set_type;
+
+ libvarpd_prop_handle_alloc;
+ libvarpd_prop_handle_free;
+ libvarpd_prop_nprops;
+ libvarpd_prop_info_fill;
+ libvarpd_prop_info;
+ libvarpd_prop_get;
+ libvarpd_prop_set;
+
+ libvarpd_overlay_lookup_quiesce;
+ libvarpd_overlay_lookup_run;
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/libvarpd/i386/Makefile b/usr/src/lib/varpd/libvarpd/i386/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/libvarpd/sparc/Makefile b/usr/src/lib/varpd/libvarpd/sparc/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/libvarpd/sparcv9/Makefile b/usr/src/lib/varpd/libvarpd/sparcv9/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/svp/Makefile b/usr/src/lib/varpd/svp/Makefile
new file mode 100644
index 0000000000..275f07bf8b
--- /dev/null
+++ b/usr/src/lib/varpd/svp/Makefile
@@ -0,0 +1,40 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/svp/Makefile.com b/usr/src/lib/varpd/svp/Makefile.com
new file mode 100644
index 0000000000..15b6540e74
--- /dev/null
+++ b/usr/src/lib/varpd/svp/Makefile.com
@@ -0,0 +1,54 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd_svp.a
+VERS = .1
+OBJECTS = libvarpd_svp.o \
+ libvarpd_svp_conn.o \
+ libvarpd_svp_crc.o \
+ libvarpd_svp_host.o \
+ libvarpd_svp_loop.o \
+ libvarpd_svp_remote.o \
+ libvarpd_svp_shootdown.o \
+ libvarpd_svp_timer.o
+
+include ../../../Makefile.lib
+include ../../Makefile.plugin
+
+LIBS = $(DYNLIB)
+
+#
+# Yes, this isn't a command, but libcmdutils does have the list(9F)
+# functions and better to use that then compile list.o yet again
+# ourselves... probably.
+#
+LDLIBS += -lc -lumem -lnvpair -lsocket -lnsl -lavl \
+ -lcmdutils -lidspace -lbunyan
+CPPFLAGS += -I../common
+
+LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
+LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN
+SRCDIR = ../common
+
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/svp/amd64/Makefile b/usr/src/lib/varpd/svp/amd64/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/svp/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp.c b/usr/src/lib/varpd/svp/common/libvarpd_svp.c
new file mode 100644
index 0000000000..58828065a1
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp.c
@@ -0,0 +1,1138 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * This plugin implements the SDC VXLAN Protocol (SVP).
+ *
+ * This plugin is designed to work with a broader distributed system that
+ * mainains a database of mappings and provides a means of looking up data and
+ * provides a stream of updates. While it is named after VXLAN, there isn't
+ * anything specific to VXLAN baked into the protocol at this time, other than
+ * that it requires both an IP address and a port; however, if there's a good
+ * reason to support others here, we can modify that.
+ *
+ * -----------
+ * Terminology
+ * -----------
+ *
+ * Throughout this module we refer to a few different kinds of addresses:
+ *
+ * VL3
+ *
+ * A VL3 address, or virtual layer 3, refers to the layer three addreses
+ * that are used by entities on an overlay network. As far as we're
+ * concerned that means that this is the IP address of an interface on an
+ * overlay network.
+ *
+ * VL2
+ *
+ * A VL2 address, or a virtual layer 2, referes to the link-layer addresses
+ * that are used by entities on an overlay network. As far as we're
+ * concerned that means that this is the MAC addresses of an interface on
+ * an overlay network.
+ *
+ * UL3
+ *
+ * A UL3, or underlay layer 3, refers to the layer three (IP) address on
+ * the underlay network.
+ *
+ * The svp plugin provides lookups from VL3->VL2, eg. the equivalent of an ARP
+ * or NDP query, and then also provides VL2->UL3 lookups.
+ *
+ * -------------------
+ * Protocol Operations
+ * -------------------
+ *
+ * The svp protocol is defined in lib/varpd/svp/common/libvarpd_svp_prot.h. It
+ * defines the basic TCP protocol that we use to communicate to hosts. At this
+ * time, it is not quite 100% implemented in both this plug-in and our primary
+ * server, sdc-portolan (see https://github.com/joyent/sdc-portolan).
+ *
+ * At this time, we don't quite support everything that we need to. Including
+ * the SVP_R_BULK_REQ and SVP_R_SHOOTDOWN.
+ *
+ * ---------------------------------
+ * General Design and Considerations
+ * ---------------------------------
+ *
+ * Every instance of the svp plugin requires the hostname and port of a server
+ * to contact. Though, we have co-opted the port 1296 (the year of the oldest
+ * extant portolan) as our default port.
+ *
+ * Each of the different instance of the plugins has a corresponding remote
+ * backend. The remote backend represents the tuple of the [ host, port ].
+ * Different instances that share the same host and port tuple will use the same
+ * backend.
+ *
+ * The backend is actually in charge of performing lookups, resolving and
+ * updating the set of remote hosts based on the DNS resolution we've been
+ * provided, and taking care of things like shootdowns.
+ *
+ * The whole plugin itself maintains an event loop and a number of threads to
+ * service that event loop. On top of that event loop, we have a simple timer
+ * backend that ticks at one second intervals and performs various callbacks,
+ * such as idle query timers, DNS resolution, connection backoff, etc. Each of
+ * the remote hosts that we obtain is wrapped up in an svp_conn_t, which manages
+ * the connection state, reconnecting, etc.
+ *
+ * All in all, the general way that this all looks like is:
+ *
+ * +----------------------------+
+ * | Plugin Instance |
+ * | svp_t |
+ * | |
+ * | varpd_provider_handle_t * -+-> varpd handle
+ * | uint64_t ----+-> varpd ID
+ * | char * ----+-> remote host
+ * | uint16_t ----+-> remote port
+ * | svp_remote_t * ---+------+-> remote backend
+ * +---------------------+------+
+ * |
+ * v
+ * +----------------------+ +----------------+
+ * | Remote backend |------------------>| Remove Backend |---> ...
+ * | svp_remote_t | | svp_remote_t |
+ * | | +----------------+
+ * | svp_remote_state_t --+-> state flags
+ * | svp_degrade_state_t -+-> degraded reason
+ * | struct addrinfo * --+-> resolved hosts
+ * | uint_t ---+-> active hosts
+ * | uint_t ---+-> DNS generation
+ * | uint_t ---+-> Reference count
+ * | uint_t ---+-> active conns
+ * | uint_t ---+-> degraded conns
+ * | list_t ---+---+-> connection list
+ * +------------------+---+
+ * |
+ * +------------------------------+-----------------+
+ * | | |
+ * v v v
+ * +-------------------+ +----------------
+ * | SVP Connection | | SVP connection | ...
+ * | svp_conn_t | | svp_conn_t |
+ * | | +----------------+
+ * | svp_event_t ----+-> event loop handle
+ * | svp_timer_t ----+-> backoff timer
+ * | svp_timer_t ----+-> query timer
+ * | int ----+-> socket fd
+ * | uint_t ----+-> generation
+ * | uint_t ----+-> current backoff
+ * | svp_conn_flags_t -+-> connection flags
+ * | svp_conn_state_t -+-> connection state
+ * | svp_conn_error_t -+-> connection error
+ * | int ---+-> last errrno
+ * | hrtime_t ---+-> activity timestamp
+ * | svp_conn_out_t ---+-> outgoing data state
+ * | svp_conn_in_t ---+-> incoming data state
+ * | list_t ---+--+-> active queries
+ * +----------------+--+
+ * |
+ * +----------------------------------+-----------------+
+ * | | |
+ * v v v
+ * +--------------------+ +-------------+
+ * | SVP Query | | SVP Query | ...
+ * | svp_query_t | | svp_query_t |
+ * | | +-------------+
+ * | svp_query_f ---+-> callback function
+ * | void * ---+-> callback arg
+ * | svp_query_state_t -+-> state flags
+ * | svp_req_t ---+-> svp prot. header
+ * | svp_query_data_t --+-> read data
+ * | svp_query_data_t --+-> write data
+ * | svp_status_t ---+-> request status
+ * +--------------------+
+ *
+ * The svp_t is the instance that we assoicate with varpd. The instance itself
+ * maintains properties and then when it's started associates with an
+ * svp_remote_t, which is the remote backend. The remote backend itself,
+ * maintains the DNS state and spins up and downs connections based on the
+ * results from DNS. By default, we query DNS every 30 seconds. For more on the
+ * connection life cycle, see the next section.
+ *
+ * By default, each connection maintains its own back off timer and list of
+ * queries it's servicing. Only one request is generally outstanding at a time
+ * and requests are round robined across the various connections.
+ *
+ * The query itself represents the svp request that's going on and keep track of
+ * its state and is a place for data that's read and written to as part of the
+ * request.
+ *
+ * Connections maintain a query timer such that if we have not received data on
+ * a socket for a certain amount of time, we kill that socket and begin a
+ * reconnection cycle with backoff.
+ *
+ * ------------------------
+ * Connection State Machine
+ * ------------------------
+ *
+ * We have a connection pool that's built upon DNS records. DNS describes the
+ * membership of the set of remote peers that make up our pool and we maintain
+ * one connection to each of them. In addition, we maintain an exponential
+ * backoff for each peer and will attempt to reconect immediately before backing
+ * off. The following are the valid states that a connection can be in:
+ *
+ * SVP_CS_ERROR An OS error has occurred on this connection,
+ * such as failure to create a socket or associate
+ * the socket with an event port. We also
+ * transition all connections to this state before
+ * we destroy them.
+ *
+ * SVP_CS_INITIAL This is the initial state of a connection, all
+ * that should exist is an unbound socket.
+ *
+ * SVP_CS_CONNECTING A call to connect has been made and we are
+ * polling for it to complete.
+ *
+ * SVP_CS_BACKOFF A connect attempt has failed and we are
+ * currently backing off, waiting to try again.
+ *
+ * SVP_CS_ACTIVE We have successfully connected to the remote
+ * system.
+ *
+ * SVP_CS_WINDDOWN This connection is going to valhalla. In other
+ * words, a previously active connection is no
+ * longer valid in DNS, so we should curb our use
+ * of it, and reap it as soon as we have other
+ * active connections.
+ *
+ * The following diagram attempts to describe our state transition scheme, and
+ * when we transition from one state to the next.
+ *
+ * |
+ * * New remote IP from DNS resolution,
+ * | not currently active in the system.
+ * |
+ * v Socket Error,
+ * +----------------+ still in DNS
+ * +----------------<---| SVP_CS_INITIAL |<----------------------*-----+
+ * | +----------------+ |
+ * | System | |
+ * | Connection . . . . . success * Successful |
+ * | failed . | connect() |
+ * | +----*---------+ | +-----------*--+ |
+ * | | | | | | |
+ * | V ^ v ^ V ^
+ * | +----------------+ +-------------------+ +---------------+
+ * +<-| SVP_CS_BACKOFF | | SVP_CS_CONNECTING | | SVP_CS_ACTIVE |
+ * | +----------------+ +-------------------+ +---------------+
+ * | V ^ V V V
+ * | Backoff wait * | | | * Removed
+ * v interval +--------------+ +-----------------<-----+ | from DNS
+ * | finished | |
+ * | V |
+ * | | V
+ * | | +-----------------+
+ * +----------------+----------<-----+-------<----| SVP_CS_WINDDOWN |
+ * | +-----------------+
+ * * . . . Fatal system, not
+ * | socket error or
+ * V quiesced after
+ * +--------------+ removal from DNS
+ * | SVP_CS_ERROR |
+ * +--------------+
+ * |
+ * * . . . Removed from DNS
+ * v
+ * +------------+
+ * | Connection |
+ * | Destroyed |
+ * +------------+
+ *
+ * --------------------------
+ * Connection Event Injection
+ * --------------------------
+ *
+ * For each connection that exists in the system, we have a timer in place that
+ * is in charge of performing timeout activity. It fires once every thirty
+ * seconds or so for a given connection and checks to ensure that we have had
+ * activity for the most recent query on the connection. If not, it terminates
+ * the connection. This is important as if we have sent all our data and are
+ * waiting for the remote end to reply, without enabling something like TCP
+ * keep-alive, we will not be notified that anything that has happened to the
+ * remote connection, for example a panic. In addition, this also protects
+ * against a server that is up, but a portolan that is not making forward
+ * progress.
+ *
+ * When a timeout occurs, we first try to disassociate any active events, which
+ * by definition must exist. Once that's done, we inject a port source user
+ * event. Now, there is a small gotcha. Let's assume for a moment that we have a
+ * pathological portolan. That means that it knows to inject activity right at
+ * the time out window. That means, that the event may be disassociated before
+ * we could get to it. If that's the case, we must _not_ inject the user event
+ * and instead, we'll let the pending event take care of it. We know that the
+ * pending event hasn't hit the main part of the loop yet, otherwise, it would
+ * have released the lock protecting our state and associated the event.
+ *
+ * ------------
+ * Notes on DNS
+ * ------------
+ *
+ * Unfortunately, doing host name resolution in a way that allows us to leverage
+ * the system's resolvers and the system's caching, require us to make blocking
+ * calls in libc via getaddrinfo(3SOCKET). If we can't reach a given server,
+ * that will tie up a thread for quite some time. To work around that fact,
+ * we're going to create a fixed number of threads and we'll use them to service
+ * our DNS requests. While this isn't ideal, until we have a sane means of
+ * integrating a DNS resolution into an event loop with say portfs, it's not
+ * going to be a fun day no matter what we do.
+ *
+ * ------
+ * Timers
+ * ------
+ *
+ * We maintain a single timer based on CLOCK_REALTIME. It's designed to fire
+ * every second. While we'd rather use CLOCK_HIGHRES just to alleviate ourselves
+ * from timer drift; however, as zones may not actually have CLOCK_HIGHRES
+ * access, we don't want them to end up in there. The timer itself is just a
+ * simple avl tree sorted by expiration time, which is stored as a tick in the
+ * future, a tick is just one second.
+ *
+ * ----------
+ * Shootdowns
+ * ----------
+ *
+ * As part of the protocol, we need to be able to handle shootdowns that inform
+ * us some of the information in the system is out of date. This information
+ * needs to be processed promptly; however, the information is hopefully going
+ * to be relatively infrequent relative to the normal flow of information.
+ *
+ * The shoot down information needs to be done on a per-backend basis. The
+ * general design is that we'll have a single query for this which can fire on a
+ * 5-10s period, we randmoize the latter part to give us a bit more load
+ * spreading. If we complete because there's no work to do, then we wait the
+ * normal period. If we complete, but there's still work to do, we'll go again
+ * after a second.
+ *
+ * A shootdown has a few different parts. We first receive a list of items to
+ * shootdown. After performing all of those, we need to acknowledge them. When
+ * that's been done successfully, we can move onto the next part. From a
+ * protocol perspective, we make a SVP_R_LOG_REQ, we get a reply, and then after
+ * processing them, send an SVP_R_LOG_RM. Only once that's been acked do we
+ * continue.
+ *
+ * However, one of the challenges that we have is that these invalidations are
+ * just that, an invalidation. For a virtual layer two request, that's fine,
+ * because the kernel supports that. However, for virtual layer three
+ * invalidations, we have a bit more work to do. These protocols, ARP and NDP,
+ * don't really support a notion of just an invalidation, instead you have to
+ * inject the new data in a gratuitous fashion.
+ *
+ * To that end, what we instead do is when we receive a VL3 invalidation, we
+ * turn that info a VL3 request. We hold the general request as outstanding
+ * until we receive all of the callbacks for the VL3 invalidations, at which
+ * point we go through and do the log removal request.
+ */
+
+#include <umem.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libnvpair.h>
+#include <strings.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <libvarpd_provider.h>
+#include "libvarpd_svp.h"
+
+bunyan_logger_t *svp_bunyan;
+static int svp_defport = 1296;
+static int svp_defuport = 1339;
+static umem_cache_t *svp_lookup_cache;
+
+typedef enum svp_lookup_type {
+ SVP_L_UNKNOWN = 0x0,
+ SVP_L_VL2 = 0x1,
+ SVP_L_VL3 = 0x2
+} svp_lookup_type_t;
+
+typedef struct svp_lookup {
+ int svl_type;
+ union {
+ struct svl_lookup_vl2 {
+ varpd_query_handle_t *svl_handle;
+ overlay_target_point_t *svl_point;
+ } svl_vl2;
+ struct svl_lookup_vl3 {
+ varpd_arp_handle_t *svl_vah;
+ uint8_t *svl_out;
+ } svl_vl3;
+ } svl_u;
+ svp_query_t svl_query;
+} svp_lookup_t;
+
+static const char *varpd_svp_props[] = {
+ "svp/host",
+ "svp/port",
+ "svp/underlay_ip",
+ "svp/underlay_port"
+};
+
+static const uint8_t svp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+int
+svp_comparator(const void *l, const void *r)
+{
+ const svp_t *ls = l;
+ const svp_t *rs = r;
+
+ if (ls->svp_vid > rs->svp_vid)
+ return (1);
+ if (ls->svp_vid < rs->svp_vid)
+ return (-1);
+ return (0);
+}
+
+static void
+svp_vl2_lookup_cb(svp_t *svp, svp_status_t status, const struct in6_addr *uip,
+ const uint16_t uport, void *arg)
+{
+ svp_lookup_t *svl = arg;
+ overlay_target_point_t *otp;
+
+ assert(svp != NULL);
+ assert(arg != NULL);
+
+ if (status != SVP_S_OK) {
+ libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
+ VARPD_LOOKUP_DROP);
+ umem_cache_free(svp_lookup_cache, svl);
+ return;
+ }
+
+ otp = svl->svl_u.svl_vl2.svl_point;
+ bcopy(uip, &otp->otp_ip, sizeof (struct in6_addr));
+ otp->otp_port = uport;
+ libvarpd_plugin_query_reply(svl->svl_u.svl_vl2.svl_handle,
+ VARPD_LOOKUP_OK);
+ umem_cache_free(svp_lookup_cache, svl);
+}
+
+static void
+svp_vl3_lookup_cb(svp_t *svp, svp_status_t status, const uint8_t *vl2mac,
+ const struct in6_addr *uip, const uint16_t uport, void *arg)
+{
+ overlay_target_point_t point;
+ svp_lookup_t *svl = arg;
+
+ assert(svp != NULL);
+ assert(svl != NULL);
+
+ if (status != SVP_S_OK) {
+ libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
+ VARPD_LOOKUP_DROP);
+ umem_cache_free(svp_lookup_cache, svl);
+ return;
+ }
+
+ /* Inject the L2 mapping before the L3 */
+ bcopy(uip, &point.otp_ip, sizeof (struct in6_addr));
+ point.otp_port = uport;
+ libvarpd_inject_varp(svp->svp_hdl, vl2mac, &point);
+
+ bcopy(vl2mac, svl->svl_u.svl_vl3.svl_out, ETHERADDRL);
+ libvarpd_plugin_arp_reply(svl->svl_u.svl_vl3.svl_vah,
+ VARPD_LOOKUP_OK);
+ umem_cache_free(svp_lookup_cache, svl);
+}
+
+static void
+svp_vl2_invalidate_cb(svp_t *svp, const uint8_t *vl2mac)
+{
+ libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
+}
+
+static void
+svp_vl3_inject_cb(svp_t *svp, const uint16_t vlan, const struct in6_addr *vl3ip,
+ const uint8_t *vl2mac, const uint8_t *targmac)
+{
+ struct in_addr v4;
+
+ /*
+ * At the moment we don't support any IPv6 related log entries, this
+ * will change soon as we develop a bit more of the IPv6 related
+ * infrastructure so we can properly test the injection.
+ */
+ if (IN6_IS_ADDR_V4MAPPED(vl3ip) == 0) {
+ return;
+ } else {
+ IN6_V4MAPPED_TO_INADDR(vl3ip, &v4);
+ if (targmac == NULL)
+ targmac = svp_bcast;
+ libvarpd_inject_arp(svp->svp_hdl, vlan, vl2mac, &v4, targmac);
+ }
+}
+
+/* ARGSUSED */
+static void
+svp_shootdown_cb(svp_t *svp, const uint8_t *vl2mac, const struct in6_addr *uip,
+ const uint16_t uport)
+{
+ /*
+ * We should probably do a conditional invlaidation here.
+ */
+ libvarpd_inject_varp(svp->svp_hdl, vl2mac, NULL);
+}
+
+static svp_cb_t svp_defops = {
+ svp_vl2_lookup_cb,
+ svp_vl3_lookup_cb,
+ svp_vl2_invalidate_cb,
+ svp_vl3_inject_cb,
+ svp_shootdown_cb
+};
+
+static boolean_t
+varpd_svp_valid_dest(overlay_plugin_dest_t dest)
+{
+ if (dest != (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+static int
+varpd_svp_create(varpd_provider_handle_t *hdl, void **outp,
+ overlay_plugin_dest_t dest)
+{
+ int ret;
+ svp_t *svp;
+
+ if (varpd_svp_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ svp = umem_zalloc(sizeof (svp_t), UMEM_DEFAULT);
+ if (svp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&svp->svp_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(svp, sizeof (svp_t));
+ return (ret);
+ }
+
+ svp->svp_port = svp_defport;
+ svp->svp_uport = svp_defuport;
+ svp->svp_cb = svp_defops;
+ svp->svp_hdl = hdl;
+ svp->svp_vid = libvarpd_plugin_vnetid(svp->svp_hdl);
+ *outp = svp;
+ return (0);
+}
+
+static int
+varpd_svp_start(void *arg)
+{
+ int ret;
+ svp_remote_t *srp;
+ svp_t *svp = arg;
+
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_host == NULL || svp->svp_port == 0 ||
+ svp->svp_huip == B_FALSE || svp->svp_uport == 0) {
+ mutex_exit(&svp->svp_lock);
+ return (EAGAIN);
+ }
+ mutex_exit(&svp->svp_lock);
+
+ if ((ret = svp_remote_find(svp->svp_host, svp->svp_port, &svp->svp_uip,
+ &srp)) != 0)
+ return (ret);
+
+ if ((ret = svp_remote_attach(srp, svp)) != 0) {
+ svp_remote_release(srp);
+ return (ret);
+ }
+
+ return (0);
+}
+
+static void
+varpd_svp_stop(void *arg)
+{
+ svp_t *svp = arg;
+
+ svp_remote_detach(svp);
+}
+
+static void
+varpd_svp_destroy(void *arg)
+{
+ svp_t *svp = arg;
+
+ if (svp->svp_host != NULL)
+ umem_free(svp->svp_host, strlen(svp->svp_host) + 1);
+
+ if (mutex_destroy(&svp->svp_lock) != 0)
+ libvarpd_panic("failed to destroy svp_t`svp_lock");
+
+ umem_free(svp, sizeof (svp_t));
+}
+
+static void
+varpd_svp_lookup(void *arg, varpd_query_handle_t *vqh,
+ const overlay_targ_lookup_t *otl, overlay_target_point_t *otp)
+{
+ svp_lookup_t *slp;
+ svp_t *svp = arg;
+
+ /*
+ * Check if this is something that we need to proxy, eg. arp or ndp.
+ */
+ if (otl->otl_sap == ETHERTYPE_ARP) {
+ libvarpd_plugin_proxy_arp(svp->svp_hdl, vqh, otl);
+ return;
+ }
+
+ if (otl->otl_dstaddr[0] == 0x33 &&
+ otl->otl_dstaddr[1] == 0x33) {
+ if (otl->otl_sap == ETHERTYPE_IPV6) {
+ libvarpd_plugin_proxy_ndp(svp->svp_hdl, vqh, otl);
+ } else {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ }
+ return;
+ }
+
+ /*
+ * Watch out for various multicast and broadcast addresses. We've
+ * already taken care of the IPv6 range above. Now we just need to
+ * handle broadcast and if the multicast bit is set, lowest bit of the
+ * first octet of the MAC, then we drop it now.
+ */
+ if (bcmp(otl->otl_dstaddr, svp_bcast, ETHERADDRL) == 0 ||
+ (otl->otl_dstaddr[0] & 0x01) == 0x01) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ /*
+ * If we have a failure to allocate memory for this, that's not good.
+ * However, telling the kernel to just drop this packet is much better
+ * than the alternative at this moment. At least we'll try again and we
+ * may have something more available to us in a little bit.
+ */
+ slp = umem_cache_alloc(svp_lookup_cache, UMEM_DEFAULT);
+ if (slp == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ slp->svl_type = SVP_L_VL2;
+ slp->svl_u.svl_vl2.svl_handle = vqh;
+ slp->svl_u.svl_vl2.svl_point = otp;
+
+ svp_remote_vl2_lookup(svp, &slp->svl_query, otl->otl_dstaddr, slp);
+}
+
+/* ARGSUSED */
+static int
+varpd_svp_nprops(void *arg, uint_t *nprops)
+{
+ *nprops = sizeof (varpd_svp_props) / sizeof (char *);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+varpd_svp_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
+{
+ switch (propid) {
+ case 0:
+ /* svp/host */
+ libvarpd_prop_set_name(vph, varpd_svp_props[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
+ libvarpd_prop_set_nodefault(vph);
+ break;
+ case 1:
+ /* svp/port */
+ libvarpd_prop_set_name(vph, varpd_svp_props[1]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
+ (void) libvarpd_prop_set_default(vph, &svp_defport,
+ sizeof (svp_defport));
+ libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
+ break;
+ case 2:
+ /* svp/underlay_ip */
+ libvarpd_prop_set_name(vph, varpd_svp_props[2]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_IP);
+ libvarpd_prop_set_nodefault(vph);
+ break;
+ case 3:
+ /* svp/underlay_port */
+ libvarpd_prop_set_name(vph, varpd_svp_props[3]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
+ (void) libvarpd_prop_set_default(vph, &svp_defuport,
+ sizeof (svp_defuport));
+ libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+varpd_svp_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
+{
+ svp_t *svp = arg;
+
+ /* svp/host */
+ if (strcmp(pname, varpd_svp_props[0]) == 0) {
+ size_t len;
+
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_host == NULL) {
+ *sizep = 0;
+ } else {
+ len = strlen(svp->svp_host) + 1;
+ if (*sizep < len) {
+ mutex_exit(&svp->svp_lock);
+ return (EOVERFLOW);
+ }
+ *sizep = len;
+ (void) strlcpy(buf, svp->svp_host, *sizep);
+ }
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ /* svp/port */
+ if (strcmp(pname, varpd_svp_props[1]) == 0) {
+ uint64_t val;
+
+ if (*sizep < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_port == 0) {
+ *sizep = 0;
+ } else {
+ val = svp->svp_port;
+ bcopy(&val, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ }
+
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ /* svp/underlay_ip */
+ if (strcmp(pname, varpd_svp_props[2]) == 0) {
+ if (*sizep > sizeof (struct in6_addr))
+ return (EOVERFLOW);
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_huip == B_FALSE) {
+ *sizep = 0;
+ } else {
+ bcopy(&svp->svp_uip, buf, sizeof (struct in6_addr));
+ *sizep = sizeof (struct in6_addr);
+ }
+ return (0);
+ }
+
+ /* svp/underlay_port */
+ if (strcmp(pname, varpd_svp_props[3]) == 0) {
+ uint64_t val;
+
+ if (*sizep < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_uport == 0) {
+ *sizep = 0;
+ } else {
+ val = svp->svp_uport;
+ bcopy(&val, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ }
+
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_svp_setprop(void *arg, const char *pname, const void *buf,
+ const uint32_t size)
+{
+ svp_t *svp = arg;
+
+ /* svp/host */
+ if (strcmp(pname, varpd_svp_props[0]) == 0) {
+ char *dup;
+ dup = umem_alloc(size, UMEM_DEFAULT);
+ (void) strlcpy(dup, buf, size);
+ if (dup == NULL)
+ return (ENOMEM);
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_host != NULL)
+ umem_free(svp->svp_host, strlen(svp->svp_host) + 1);
+ svp->svp_host = dup;
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ /* svp/port */
+ if (strcmp(pname, varpd_svp_props[1]) == 0) {
+ const uint64_t *valp = buf;
+ if (size < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ if (*valp == 0 || *valp > UINT16_MAX)
+ return (EINVAL);
+
+ mutex_enter(&svp->svp_lock);
+ svp->svp_port = (uint16_t)*valp;
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ /* svp/underlay_ip */
+ if (strcmp(pname, varpd_svp_props[2]) == 0) {
+ const struct in6_addr *ipv6 = buf;
+
+ if (size < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+
+ if (IN6_IS_ADDR_V4COMPAT(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_MULTICAST(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_6TO4(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_V4MAPPED(ipv6)) {
+ ipaddr_t v4;
+ IN6_V4MAPPED_TO_IPADDR(ipv6, v4);
+ if (IN_MULTICAST(v4))
+ return (EINVAL);
+ }
+
+ mutex_enter(&svp->svp_lock);
+ bcopy(buf, &svp->svp_uip, sizeof (struct in6_addr));
+ svp->svp_huip = B_TRUE;
+ mutex_exit(&svp->svp_lock);
+ return (0);
+ }
+
+ /* svp/underlay_port */
+ if (strcmp(pname, varpd_svp_props[3]) == 0) {
+ const uint64_t *valp = buf;
+ if (size < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ if (*valp == 0 || *valp > UINT16_MAX)
+ return (EINVAL);
+
+ mutex_enter(&svp->svp_lock);
+ svp->svp_uport = (uint16_t)*valp;
+ mutex_exit(&svp->svp_lock);
+
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_svp_save(void *arg, nvlist_t *nvp)
+{
+ int ret;
+ svp_t *svp = arg;
+
+ mutex_enter(&svp->svp_lock);
+ if (svp->svp_host != NULL) {
+ if ((ret = nvlist_add_string(nvp, varpd_svp_props[0],
+ svp->svp_host)) != 0) {
+ mutex_exit(&svp->svp_lock);
+ return (ret);
+ }
+ }
+
+ if (svp->svp_port != 0) {
+ if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[1],
+ svp->svp_port)) != 0) {
+ mutex_exit(&svp->svp_lock);
+ return (ret);
+ }
+ }
+
+ if (svp->svp_huip == B_TRUE) {
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, &svp->svp_uip, buf, sizeof (buf)) ==
+ NULL)
+ libvarpd_panic("unexpected inet_ntop failure: %d",
+ errno);
+
+ if ((ret = nvlist_add_string(nvp, varpd_svp_props[2],
+ buf)) != 0) {
+ mutex_exit(&svp->svp_lock);
+ return (ret);
+ }
+ }
+
+ if (svp->svp_uport != 0) {
+ if ((ret = nvlist_add_uint16(nvp, varpd_svp_props[3],
+ svp->svp_uport)) != 0) {
+ mutex_exit(&svp->svp_lock);
+ return (ret);
+ }
+ }
+
+ mutex_exit(&svp->svp_lock);
+ return (0);
+}
+
+static int
+varpd_svp_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
+ overlay_plugin_dest_t dest, void **outp)
+{
+ int ret;
+ svp_t *svp;
+ char *ipstr, *hstr;
+
+ if (varpd_svp_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ if ((ret = varpd_svp_create(hdl, (void **)&svp, dest)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[0],
+ &hstr)) != 0) {
+ if (ret != ENOENT) {
+ varpd_svp_destroy(svp);
+ return (ret);
+ }
+ svp->svp_host = NULL;
+ } else {
+ size_t blen = strlen(hstr) + 1;
+ svp->svp_host = umem_alloc(blen, UMEM_DEFAULT);
+ (void) strlcpy(svp->svp_host, hstr, blen);
+ }
+
+ if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[1],
+ &svp->svp_port)) != 0) {
+ if (ret != ENOENT) {
+ varpd_svp_destroy(svp);
+ return (ret);
+ }
+ svp->svp_port = 0;
+ }
+
+ if ((ret = nvlist_lookup_string(nvp, varpd_svp_props[2],
+ &ipstr)) != 0) {
+ if (ret != ENOENT) {
+ varpd_svp_destroy(svp);
+ return (ret);
+ }
+ svp->svp_huip = B_FALSE;
+ } else {
+ ret = inet_pton(AF_INET6, ipstr, &svp->svp_uip);
+ if (ret == -1) {
+ assert(errno == EAFNOSUPPORT);
+ libvarpd_panic("unexpected inet_pton failure: %d",
+ errno);
+ }
+
+ if (ret == 0) {
+ varpd_svp_destroy(svp);
+ return (EINVAL);
+ }
+ svp->svp_huip = B_TRUE;
+ }
+
+ if ((ret = nvlist_lookup_uint16(nvp, varpd_svp_props[3],
+ &svp->svp_uport)) != 0) {
+ if (ret != ENOENT) {
+ varpd_svp_destroy(svp);
+ return (ret);
+ }
+ svp->svp_uport = 0;
+ }
+
+ svp->svp_hdl = hdl;
+ *outp = svp;
+ return (0);
+}
+
+static void
+varpd_svp_arp(void *arg, varpd_arp_handle_t *vah, int type,
+ const struct sockaddr *sock, uint8_t *out)
+{
+ svp_t *svp = arg;
+ svp_lookup_t *svl;
+
+ if (type != VARPD_QTYPE_ETHERNET) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ svl = umem_cache_alloc(svp_lookup_cache, UMEM_DEFAULT);
+ if (svl == NULL) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ svl->svl_type = SVP_L_VL3;
+ svl->svl_u.svl_vl3.svl_vah = vah;
+ svl->svl_u.svl_vl3.svl_out = out;
+ svp_remote_vl3_lookup(svp, &svl->svl_query, sock, svl);
+}
+
+static const varpd_plugin_ops_t varpd_svp_ops = {
+ 0,
+ varpd_svp_create,
+ varpd_svp_start,
+ varpd_svp_stop,
+ varpd_svp_destroy,
+ NULL,
+ varpd_svp_lookup,
+ varpd_svp_nprops,
+ varpd_svp_propinfo,
+ varpd_svp_getprop,
+ varpd_svp_setprop,
+ varpd_svp_save,
+ varpd_svp_restore,
+ varpd_svp_arp,
+ NULL
+};
+
+static int
+svp_bunyan_init(void)
+{
+ int ret;
+
+ if ((ret = bunyan_init("svp", &svp_bunyan)) != 0)
+ return (ret);
+ ret = bunyan_stream_add(svp_bunyan, "stderr", BUNYAN_L_INFO,
+ bunyan_stream_fd, (void *)STDERR_FILENO);
+ if (ret != 0)
+ bunyan_fini(svp_bunyan);
+ return (ret);
+}
+
+static void
+svp_bunyan_fini(void)
+{
+ if (svp_bunyan != NULL)
+ bunyan_fini(svp_bunyan);
+}
+
+#pragma init(varpd_svp_init)
+static void
+varpd_svp_init(void)
+{
+ int err;
+ varpd_plugin_register_t *vpr;
+
+ if (svp_bunyan_init() != 0)
+ return;
+
+ if ((err = svp_host_init()) != 0) {
+ (void) bunyan_error(svp_bunyan, "failed to init host subsystem",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_bunyan_fini();
+ return;
+ }
+
+ svp_lookup_cache = umem_cache_create("svp_lookup",
+ sizeof (svp_lookup_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+ if (svp_lookup_cache == NULL) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to create svp_lookup cache",
+ BUNYAN_T_INT32, "error", errno,
+ BUNYAN_T_END);
+ svp_bunyan_fini();
+ return;
+ }
+
+ if ((err = svp_event_init()) != 0) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to init event subsystem",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_bunyan_fini();
+ umem_cache_destroy(svp_lookup_cache);
+ return;
+ }
+
+ if ((err = svp_timer_init()) != 0) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to init timer subsystem",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_event_fini();
+ umem_cache_destroy(svp_lookup_cache);
+ svp_bunyan_fini();
+ return;
+ }
+
+ if ((err = svp_remote_init()) != 0) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to init remote subsystem",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_event_fini();
+ umem_cache_destroy(svp_lookup_cache);
+ svp_bunyan_fini();
+ return;
+ }
+
+ vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
+ if (vpr == NULL) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to alloc varpd plugin",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_remote_fini();
+ svp_event_fini();
+ umem_cache_destroy(svp_lookup_cache);
+ svp_bunyan_fini();
+ return;
+ }
+
+ vpr->vpr_mode = OVERLAY_TARGET_DYNAMIC;
+ vpr->vpr_name = "svp";
+ vpr->vpr_ops = &varpd_svp_ops;
+
+ if ((err = libvarpd_plugin_register(vpr)) != 0) {
+ (void) bunyan_error(svp_bunyan,
+ "failed to register varpd plugin",
+ BUNYAN_T_INT32, "error", err,
+ BUNYAN_T_END);
+ svp_remote_fini();
+ svp_event_fini();
+ umem_cache_destroy(svp_lookup_cache);
+ svp_bunyan_fini();
+
+ }
+ libvarpd_plugin_free(vpr);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp.h b/usr/src/lib/varpd/svp/common/libvarpd_svp.h
new file mode 100644
index 0000000000..8192b842ce
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp.h
@@ -0,0 +1,357 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_SVP_H
+#define _LIBVARPD_SVP_H
+
+/*
+ * Implementation details of the SVP plugin and the SVP protocol.
+ */
+
+#include <netinet/in.h>
+#include <sys/ethernet.h>
+#include <thread.h>
+#include <synch.h>
+#include <libvarpd_provider.h>
+#include <sys/avl.h>
+#include <port.h>
+#include <sys/list.h>
+#include <bunyan.h>
+
+#include <libvarpd_svp_prot.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct svp svp_t;
+typedef struct svp_remote svp_remote_t;
+typedef struct svp_conn svp_conn_t;
+typedef struct svp_query svp_query_t;
+
+typedef void (*svp_event_f)(port_event_t *, void *);
+
+typedef struct svp_event {
+ svp_event_f se_func;
+ void *se_arg;
+ int se_events;
+} svp_event_t;
+
+typedef void (*svp_timer_f)(void *);
+
+typedef struct svp_timer {
+ svp_timer_f st_func; /* Timer callback function */
+ void *st_arg; /* Timer callback arg */
+ boolean_t st_oneshot; /* Is timer a one shot? */
+ uint32_t st_value; /* periodic or one-shot time */
+ /* Fields below here are private to the svp_timer implementaiton */
+ uint64_t st_expire; /* Next expiration */
+ boolean_t st_delivering; /* Are we currently delivering this */
+ avl_node_t st_link;
+} svp_timer_t;
+
+/*
+ * Note, both the svp_log_ack_t and svp_lrm_req_t are not part of this structure
+ * as they are rather variable sized data and we don't want to constrain their
+ * size. Instead, the rdata and wdata members must be set appropriately.
+ */
+typedef union svp_query_data {
+ svp_vl2_req_t sqd_vl2r;
+ svp_vl2_ack_t sqd_vl2a;
+ svp_vl3_req_t sdq_vl3r;
+ svp_vl3_ack_t sdq_vl3a;
+ svp_log_req_t sdq_logr;
+ svp_lrm_ack_t sdq_lrma;
+} svp_query_data_t;
+
+typedef void (*svp_query_f)(svp_query_t *, void *);
+
+typedef enum svp_query_state {
+ SVP_QUERY_INIT = 0x00,
+ SVP_QUERY_WRITING = 0x01,
+ SVP_QUERY_READING = 0x02,
+ SVP_QUERY_FINISHED = 0x03
+} svp_query_state_t;
+
+/*
+ * The query structure is usable for all forms of svp queries that end up
+ * getting passed across. Right now it's optimized for the fixed size data
+ * requests as opposed to requests whose responses will always be streaming in
+ * nature. Though, the streaming requests are the less common ones we have. We
+ * may need to make additional changes for those.
+ */
+struct svp_query {
+ list_node_t sq_lnode; /* List entry */
+ svp_query_f sq_func; /* Callback function */
+ svp_query_state_t sq_state; /* Query state */
+ void *sq_arg; /* Callback function arg */
+ svp_t *sq_svp; /* Pointer back to svp_t */
+ svp_req_t sq_header; /* Header for the query */
+ svp_query_data_t sq_rdun; /* Union for read data */
+ svp_query_data_t sq_wdun; /* Union for write data */
+ svp_status_t sq_status; /* Query response status */
+ size_t sq_size; /* Query response size */
+ void *sq_rdata; /* Read data pointer */
+ size_t sq_rsize; /* Read data size */
+ void *sq_wdata; /* Write data pointer */
+ size_t sq_wsize; /* Write data size */
+ hrtime_t sq_acttime; /* Last I/O activity time */
+};
+
+typedef enum svp_conn_state {
+ SVP_CS_ERROR = 0x00,
+ SVP_CS_INITIAL = 0x01,
+ SVP_CS_CONNECTING = 0x02,
+ SVP_CS_BACKOFF = 0x03,
+ SVP_CS_ACTIVE = 0x04,
+ SVP_CS_WINDDOWN = 0x05
+} svp_conn_state_t;
+
+typedef enum svp_conn_error {
+ SVP_CE_NONE = 0x00,
+ SVP_CE_ASSOCIATE = 0x01,
+ SVP_CE_NOPOLLOUT = 0x02,
+ SVP_CE_SOCKET = 0x03
+} svp_conn_error_t;
+
+typedef enum svp_conn_flags {
+ SVP_CF_ADDED = 0x01,
+ SVP_CF_DEGRADED = 0x02,
+ SVP_CF_REAP = 0x04,
+ SVP_CF_TEARDOWN = 0x08,
+ SVP_CF_UFLAG = 0x0c,
+ SVP_CF_USER = 0x10
+} svp_conn_flags_t;
+
+typedef struct svp_conn_out {
+ svp_query_t *sco_query;
+ size_t sco_offset;
+} svp_conn_out_t;
+
+typedef struct svp_conn_in {
+ svp_query_t *sci_query;
+ svp_req_t sci_req;
+ size_t sci_offset;
+} svp_conn_in_t;
+
+struct svp_conn {
+ svp_remote_t *sc_remote; /* RO */
+ struct in6_addr sc_addr; /* RO */
+ list_node_t sc_rlist; /* svp_remote_t`sr_lock */
+ mutex_t sc_lock;
+ svp_event_t sc_event;
+ svp_timer_t sc_btimer;
+ svp_timer_t sc_qtimer;
+ int sc_socket;
+ uint_t sc_gen;
+ uint_t sc_nbackoff;
+ svp_conn_flags_t sc_flags;
+ svp_conn_state_t sc_cstate;
+ svp_conn_error_t sc_error;
+ int sc_errno;
+ list_t sc_queries;
+ svp_conn_out_t sc_output;
+ svp_conn_in_t sc_input;
+};
+
+typedef enum svp_remote_state {
+ SVP_RS_LOOKUP_SCHEDULED = 0x01, /* On the DNS Queue */
+ SVP_RS_LOOKUP_INPROGRESS = 0x02, /* Doing a DNS lookup */
+ SVP_RS_LOOKUP_VALID = 0x04 /* addrinfo valid */
+} svp_remote_state_t;
+
+/*
+ * These series of bit-based flags should be ordered such that the most severe
+ * is first. We only can set one message that user land can see, so if more than
+ * one is set we want to make sure that one is there.
+ */
+typedef enum svp_degrade_state {
+ SVP_RD_DNS_FAIL = 0x01, /* DNS Resolution Failure */
+ SVP_RD_REMOTE_FAIL = 0x02, /* cannot reach any remote peers */
+ SVP_RD_ALL = 0x03 /* Only suitable for restore */
+} svp_degrade_state_t;
+
+typedef enum svp_shootdown_flags {
+ SVP_SD_RUNNING = 0x01,
+ SVP_SD_QUIESCE = 0x02,
+ SVP_SD_DORM = 0x04
+} svp_shootdown_flags_t;
+
+/*
+ * There is a single svp_sdlog_t per svp_remote_t. It maintains its own lock and
+ * condition variables. See the big theory statement for more information on how
+ * it's used.
+ */
+typedef struct svp_sdlog {
+ mutex_t sdl_lock;
+ cond_t sdl_cond;
+ uint_t sdl_ref;
+ svp_timer_t sdl_timer;
+ svp_shootdown_flags_t sdl_flags;
+ svp_query_t sdl_query;
+ void *sdl_logack;
+ void *sdl_logrm;
+ void *sdl_remote;
+} svp_sdlog_t;
+
+struct svp_remote {
+ char *sr_hostname; /* RO */
+ uint16_t sr_rport; /* RO */
+ struct in6_addr sr_uip; /* RO */
+ avl_node_t sr_gnode; /* svp_remote_lock */
+ svp_remote_t *sr_nexthost; /* svp_host_lock */
+ mutex_t sr_lock;
+ cond_t sr_cond;
+ svp_remote_state_t sr_state;
+ svp_degrade_state_t sr_degrade;
+ struct addrinfo *sr_addrinfo;
+ avl_tree_t sr_tree;
+ uint_t sr_count; /* active count */
+ uint_t sr_gen;
+ uint_t sr_tconns; /* total conns + dconns */
+ uint_t sr_ndconns; /* number of degraded conns */
+ list_t sr_conns; /* all conns */
+ svp_sdlog_t sr_shoot;
+};
+
+/*
+ * We have a bunch of different things that we get back from the API at the
+ * plug-in layer. These include:
+ *
+ * o OOB Shootdowns
+ * o VL3->VL2 Lookups
+ * o VL2->UL3 Lookups
+ * o VL2 Log invalidations
+ * o VL3 Log injections
+ */
+typedef void (*svp_vl2_lookup_f)(svp_t *, svp_status_t, const struct in6_addr *,
+ const uint16_t, void *);
+typedef void (*svp_vl3_lookup_f)(svp_t *, svp_status_t, const uint8_t *,
+ const struct in6_addr *, const uint16_t, void *);
+typedef void (*svp_vl2_invalidation_f)(svp_t *, const uint8_t *);
+typedef void (*svp_vl3_inject_f)(svp_t *, const uint16_t,
+ const struct in6_addr *, const uint8_t *, const uint8_t *);
+typedef void (*svp_shootdown_f)(svp_t *, const uint8_t *,
+ const struct in6_addr *, const uint16_t uport);
+
+typedef struct svp_cb {
+ svp_vl2_lookup_f scb_vl2_lookup;
+ svp_vl3_lookup_f scb_vl3_lookup;
+ svp_vl2_invalidation_f scb_vl2_invalidate;
+ svp_vl3_inject_f scb_vl3_inject;
+ svp_shootdown_f scb_shootdown;
+} svp_cb_t;
+
+/*
+ * Core implementation structure.
+ */
+struct svp {
+ overlay_plugin_dest_t svp_dest; /* RO */
+ varpd_provider_handle_t *svp_hdl; /* RO */
+ svp_cb_t svp_cb; /* RO */
+ uint64_t svp_vid; /* RO */
+ avl_node_t svp_rlink; /* Owned by svp_remote */
+ svp_remote_t *svp_remote; /* RO iff started */
+ mutex_t svp_lock;
+ char *svp_host; /* svp_lock */
+ uint16_t svp_port; /* svp_lock */
+ uint16_t svp_uport; /* svp_lock */
+ boolean_t svp_huip; /* svp_lock */
+ struct in6_addr svp_uip; /* svp_lock */
+};
+
+extern bunyan_logger_t *svp_bunyan;
+
+extern int svp_remote_find(char *, uint16_t, struct in6_addr *,
+ svp_remote_t **);
+extern int svp_remote_attach(svp_remote_t *, svp_t *);
+extern void svp_remote_detach(svp_t *);
+extern void svp_remote_release(svp_remote_t *);
+extern void svp_remote_vl3_lookup(svp_t *, svp_query_t *,
+ const struct sockaddr *, void *);
+extern void svp_remote_vl2_lookup(svp_t *, svp_query_t *, const uint8_t *,
+ void *);
+
+/*
+ * Init functions
+ */
+extern int svp_remote_init(void);
+extern void svp_remote_fini(void);
+extern int svp_event_init(void);
+extern int svp_event_timer_init(svp_event_t *);
+extern void svp_event_fini(void);
+extern int svp_host_init(void);
+extern int svp_timer_init(void);
+
+/*
+ * Timers
+ */
+extern int svp_tickrate;
+extern void svp_timer_add(svp_timer_t *);
+extern void svp_timer_remove(svp_timer_t *);
+
+/*
+ * Event loop management
+ */
+extern int svp_event_associate(svp_event_t *, int);
+extern int svp_event_dissociate(svp_event_t *, int);
+extern int svp_event_inject(svp_event_t *);
+
+/*
+ * Connection manager
+ */
+extern int svp_conn_create(svp_remote_t *, const struct in6_addr *);
+extern void svp_conn_destroy(svp_conn_t *);
+extern void svp_conn_fallout(svp_conn_t *);
+extern void svp_conn_queue(svp_conn_t *, svp_query_t *);
+
+/*
+ * FMA related
+ */
+extern void svp_remote_degrade(svp_remote_t *, svp_degrade_state_t);
+extern void svp_remote_restore(svp_remote_t *, svp_degrade_state_t);
+
+/*
+ * Misc.
+ */
+extern int svp_comparator(const void *, const void *);
+extern void svp_remote_reassign(svp_remote_t *, svp_conn_t *);
+extern void svp_remote_resolved(svp_remote_t *, struct addrinfo *);
+extern void svp_host_queue(svp_remote_t *);
+extern void svp_query_release(svp_query_t *);
+extern void svp_query_crc32(svp_req_t *, void *, size_t);
+
+/*
+ * Shootdown related
+ */
+extern void svp_remote_shootdown_vl3(svp_remote_t *, svp_log_vl3_t *,
+ svp_sdlog_t *);
+extern void svp_remote_shootdown_vl2(svp_remote_t *, svp_log_vl2_t *);
+extern void svp_remote_log_request(svp_remote_t *, svp_query_t *, void *,
+ size_t);
+extern void svp_remote_lrm_request(svp_remote_t *, svp_query_t *, void *,
+ size_t);
+extern void svp_shootdown_logr_cb(svp_remote_t *, svp_status_t, void *, size_t);
+extern void svp_shootdown_lrm_cb(svp_remote_t *, svp_status_t);
+extern void svp_shootdown_vl3_cb(svp_status_t, svp_log_vl3_t *, svp_sdlog_t *);
+extern int svp_shootdown_init(svp_remote_t *);
+extern void svp_shootdown_fini(svp_remote_t *);
+extern void svp_shootdown_start(svp_remote_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_SVP_H */
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_conn.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_conn.c
new file mode 100644
index 0000000000..5d19f8a388
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_conn.c
@@ -0,0 +1,1031 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Logic to manage an individual connection to a remote host.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+#include <assert.h>
+#include <umem.h>
+#include <errno.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/uio.h>
+#include <sys/debug.h>
+
+#include <libvarpd_svp.h>
+
+int svp_conn_query_timeout = 30;
+static int svp_conn_backoff_tbl[] = { 1, 2, 4, 8, 16, 32 };
+static int svp_conn_nbackoff = sizeof (svp_conn_backoff_tbl) / sizeof (int);
+
+typedef enum svp_conn_act {
+ SVP_RA_NONE = 0x00,
+ SVP_RA_DEGRADE = 0x01,
+ SVP_RA_RESTORE = 0x02,
+ SVP_RA_ERROR = 0x03,
+ SVP_RA_CLEANUP = 0x04
+} svp_conn_act_t;
+
+static void
+svp_conn_inject(svp_conn_t *scp)
+{
+ int ret;
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (scp->sc_flags & SVP_CF_USER)
+ return;
+ scp->sc_flags |= SVP_CF_USER;
+ if ((ret = svp_event_inject(&scp->sc_event)) != 0)
+ libvarpd_panic("failed to inject event: %d\n", ret);
+}
+
+static void
+svp_conn_degrade(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (scp->sc_flags & SVP_CF_DEGRADED)
+ return;
+
+ scp->sc_flags |= SVP_CF_DEGRADED;
+ srp->sr_ndconns++;
+ if (srp->sr_ndconns == srp->sr_tconns)
+ svp_remote_degrade(srp, SVP_RD_REMOTE_FAIL);
+}
+
+static void
+svp_conn_restore(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (!(scp->sc_flags & SVP_CF_DEGRADED))
+ return;
+
+ scp->sc_flags &= ~SVP_CF_DEGRADED;
+ if (srp->sr_ndconns == srp->sr_tconns)
+ svp_remote_restore(srp, SVP_RD_REMOTE_FAIL);
+ srp->sr_ndconns--;
+}
+
+static void
+svp_conn_add(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (scp->sc_flags & SVP_CF_ADDED)
+ return;
+
+ list_insert_tail(&srp->sr_conns, scp);
+ scp->sc_flags |= SVP_CF_ADDED;
+ srp->sr_tconns++;
+}
+
+static void
+svp_conn_remove(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (!(scp->sc_flags & SVP_CF_ADDED))
+ return;
+
+ scp->sc_flags &= ~SVP_CF_ADDED;
+ if (scp->sc_flags & SVP_CF_DEGRADED)
+ srp->sr_ndconns--;
+ srp->sr_tconns--;
+ if (srp->sr_tconns == srp->sr_ndconns)
+ svp_remote_degrade(srp, SVP_RD_REMOTE_FAIL);
+}
+
+static svp_query_t *
+svp_conn_query_find(svp_conn_t *scp, uint32_t id)
+{
+ svp_query_t *sqp;
+
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ for (sqp = list_head(&scp->sc_queries); sqp != NULL;
+ sqp = list_next(&scp->sc_queries, sqp)) {
+ if (sqp->sq_header.svp_id == id)
+ break;
+ }
+
+ return (sqp);
+}
+
+static svp_conn_act_t
+svp_conn_backoff(svp_conn_t *scp)
+{
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ if (close(scp->sc_socket) != 0)
+ libvarpd_panic("failed to close socket %d: %d\n",
+ scp->sc_socket, errno);
+ scp->sc_socket = -1;
+
+ scp->sc_cstate = SVP_CS_BACKOFF;
+ scp->sc_nbackoff++;
+ if (scp->sc_nbackoff >= svp_conn_nbackoff) {
+ scp->sc_btimer.st_value =
+ svp_conn_backoff_tbl[svp_conn_nbackoff - 1];
+ } else {
+ scp->sc_btimer.st_value =
+ svp_conn_backoff_tbl[scp->sc_nbackoff - 1];
+ }
+ svp_timer_add(&scp->sc_btimer);
+
+ if (scp->sc_nbackoff > svp_conn_nbackoff)
+ return (SVP_RA_DEGRADE);
+ return (SVP_RA_NONE);
+}
+
+static svp_conn_act_t
+svp_conn_connect(svp_conn_t *scp)
+{
+ int ret;
+ struct sockaddr_in6 in6;
+
+ assert(MUTEX_HELD(&scp->sc_lock));
+ assert(scp->sc_cstate == SVP_CS_BACKOFF ||
+ scp->sc_cstate == SVP_CS_INITIAL);
+ assert(scp->sc_socket == -1);
+ if (scp->sc_cstate == SVP_CS_INITIAL)
+ scp->sc_nbackoff = 0;
+
+ scp->sc_socket = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (scp->sc_socket == -1) {
+ scp->sc_error = SVP_CE_SOCKET;
+ scp->sc_errno = errno;
+ scp->sc_cstate = SVP_CS_ERROR;
+ return (SVP_RA_DEGRADE);
+ }
+
+ bzero(&in6, sizeof (struct sockaddr_in6));
+ in6.sin6_family = AF_INET6;
+ in6.sin6_port = htons(scp->sc_remote->sr_rport);
+ bcopy(&scp->sc_addr, &in6.sin6_addr, sizeof (struct in6_addr));
+ ret = connect(scp->sc_socket, (struct sockaddr *)&in6,
+ sizeof (struct sockaddr_in6));
+ if (ret != 0) {
+ boolean_t async = B_FALSE;
+
+ switch (errno) {
+ case EACCES:
+ case EADDRINUSE:
+ case EAFNOSUPPORT:
+ case EALREADY:
+ case EBADF:
+ case EISCONN:
+ case ELOOP:
+ case ENOENT:
+ case ENOSR:
+ case EWOULDBLOCK:
+ libvarpd_panic("unanticipated connect errno %d", errno);
+ break;
+ case EINPROGRESS:
+ case EINTR:
+ async = B_TRUE;
+ default:
+ break;
+ }
+
+ /*
+ * So, we will be connecting to this in the future, advance our
+ * state and make sure that we poll for the next round.
+ */
+ if (async == B_TRUE) {
+ scp->sc_cstate = SVP_CS_CONNECTING;
+ scp->sc_event.se_events = POLLOUT | POLLHUP;
+ ret = svp_event_associate(&scp->sc_event,
+ scp->sc_socket);
+ if (ret == 0)
+ return (SVP_RA_NONE);
+ scp->sc_error = SVP_CE_ASSOCIATE;
+ scp->sc_errno = ret;
+ scp->sc_cstate = SVP_CS_ERROR;
+ return (SVP_RA_DEGRADE);
+ } else {
+ /*
+ * This call failed, which means that we obtained one of
+ * the following:
+ *
+ * EADDRNOTAVAIL
+ * ECONNREFUSED
+ * EIO
+ * ENETUNREACH
+ * EHOSTUNREACH
+ * ENXIO
+ * ETIMEDOUT
+ *
+ * Therefore we need to set ourselves into backoff and
+ * wait for that to clear up.
+ */
+ return (svp_conn_backoff(scp));
+ }
+ }
+
+ /*
+ * We've connected. Successfully move ourselves to the bound
+ * state and start polling.
+ */
+ scp->sc_cstate = SVP_CS_ACTIVE;
+ scp->sc_event.se_events = POLLIN | POLLRDNORM | POLLHUP;
+ ret = svp_event_associate(&scp->sc_event, scp->sc_socket);
+ if (ret == 0)
+ return (SVP_RA_RESTORE);
+ scp->sc_error = SVP_CE_ASSOCIATE;
+ scp->sc_cstate = SVP_CS_ERROR;
+
+ return (SVP_RA_DEGRADE);
+}
+
+/*
+ * This should be the first call we get after a connect. If we have successfully
+ * connected, we should see a writeable event. We may also see an error or a
+ * hang up. In either of these cases, we transition to error mode. If there is
+ * also a readable event, we ignore it at the moment and just let a
+ * reassociation pick it up so we can simplify the set of state transitions that
+ * we have.
+ */
+static svp_conn_act_t
+svp_conn_poll_connect(port_event_t *pe, svp_conn_t *scp)
+{
+ int ret, err;
+ socklen_t sl = sizeof (err);
+ if (!(pe->portev_events & POLLOUT)) {
+ scp->sc_errno = 0;
+ scp->sc_error = SVP_CE_NOPOLLOUT;
+ scp->sc_cstate = SVP_CS_ERROR;
+ return (SVP_RA_DEGRADE);
+ }
+
+ ret = getsockopt(scp->sc_socket, SOL_SOCKET, SO_ERROR, &err, &sl);
+ if (ret != 0)
+ libvarpd_panic("unanticipated getsockopt error");
+ if (err != 0) {
+ return (svp_conn_backoff(scp));
+ }
+
+ scp->sc_cstate = SVP_CS_ACTIVE;
+ scp->sc_event.se_events = POLLIN | POLLRDNORM | POLLHUP;
+ ret = svp_event_associate(&scp->sc_event, scp->sc_socket);
+ if (ret == 0)
+ return (SVP_RA_RESTORE);
+ scp->sc_error = SVP_CE_ASSOCIATE;
+ scp->sc_errno = ret;
+ scp->sc_cstate = SVP_CS_ERROR;
+ return (SVP_RA_DEGRADE);
+}
+
+static svp_conn_act_t
+svp_conn_pollout(svp_conn_t *scp)
+{
+ svp_query_t *sqp;
+ svp_req_t *req;
+ size_t off;
+ struct iovec iov[2];
+ int nvecs = 0;
+ ssize_t ret;
+
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ /*
+ * We need to find a query and start writing it out.
+ */
+ if (scp->sc_output.sco_query == NULL) {
+ for (sqp = list_head(&scp->sc_queries); sqp != NULL;
+ sqp = list_next(&scp->sc_queries, sqp)) {
+ if (sqp->sq_state != SVP_QUERY_INIT)
+ continue;
+ break;
+ }
+
+ if (sqp == NULL) {
+ scp->sc_event.se_events &= ~POLLOUT;
+ return (SVP_RA_NONE);
+ }
+
+ scp->sc_output.sco_query = sqp;
+ scp->sc_output.sco_offset = 0;
+ sqp->sq_state = SVP_QUERY_WRITING;
+ svp_query_crc32(&sqp->sq_header, sqp->sq_rdata, sqp->sq_rsize);
+ }
+
+ sqp = scp->sc_output.sco_query;
+ req = &sqp->sq_header;
+ off = scp->sc_output.sco_offset;
+ if (off < sizeof (svp_req_t)) {
+ iov[nvecs].iov_base = (void *)((uintptr_t)req + off);
+ iov[nvecs].iov_len = sizeof (svp_req_t) - off;
+ nvecs++;
+ off = 0;
+ } else {
+ off -= sizeof (svp_req_t);
+ }
+
+ iov[nvecs].iov_base = (void *)((uintptr_t)sqp->sq_rdata + off);
+ iov[nvecs].iov_len = sqp->sq_rsize - off;
+ nvecs++;
+
+ do {
+ ret = writev(scp->sc_socket, iov, nvecs);
+ } while (ret == -1 && errno == EAGAIN);
+ if (ret == -1) {
+ switch (errno) {
+ case EAGAIN:
+ scp->sc_event.se_events |= POLLOUT;
+ return (SVP_RA_NONE);
+ case EIO:
+ case ENXIO:
+ case ECONNRESET:
+ return (SVP_RA_ERROR);
+ default:
+ libvarpd_panic("unexpected errno: %d", errno);
+ }
+ }
+
+ sqp->sq_acttime = gethrtime();
+ scp->sc_output.sco_offset += ret;
+ if (ret >= sizeof (svp_req_t) + sqp->sq_rsize) {
+ sqp->sq_state = SVP_QUERY_READING;
+ scp->sc_output.sco_query = NULL;
+ scp->sc_output.sco_offset = 0;
+ scp->sc_event.se_events |= POLLOUT;
+ }
+ return (SVP_RA_NONE);
+}
+
+static boolean_t
+svp_conn_pollin_validate(svp_conn_t *scp)
+{
+ svp_query_t *sqp;
+ uint32_t nsize;
+ uint16_t nvers, nop;
+ svp_req_t *resp = &scp->sc_input.sci_req;
+
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ nvers = ntohs(resp->svp_ver);
+ nop = ntohs(resp->svp_op);
+ nsize = ntohl(resp->svp_size);
+
+ if (nvers != SVP_CURRENT_VERSION) {
+ (void) bunyan_warn(svp_bunyan, "unsupported version",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+
+ if (nop != SVP_R_VL2_ACK && nop != SVP_R_VL3_ACK &&
+ nop != SVP_R_LOG_ACK && nop != SVP_R_LOG_RM_ACK) {
+ (void) bunyan_warn(svp_bunyan, "unsupported operation",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+
+ sqp = svp_conn_query_find(scp, resp->svp_id);
+ if (sqp == NULL) {
+ (void) bunyan_warn(svp_bunyan, "unknown response id",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+
+ if (sqp->sq_state != SVP_QUERY_READING) {
+ (void) bunyan_warn(svp_bunyan,
+ "got response for unexpecting query",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_INT32, "query_state", sqp->sq_state,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+
+ if ((nop == SVP_R_VL2_ACK && nsize != sizeof (svp_vl2_ack_t)) ||
+ (nop == SVP_R_VL3_ACK && nsize != sizeof (svp_vl3_ack_t)) ||
+ (nop == SVP_R_LOG_RM_ACK && nsize != sizeof (svp_lrm_ack_t))) {
+ (void) bunyan_warn(svp_bunyan, "response size too large",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_INT32, "response_size", nsize,
+ BUNYAN_T_INT32, "expected_size", nop == SVP_R_VL2_ACK ?
+ sizeof (svp_vl2_ack_t) : sizeof (svp_vl3_ack_t),
+ BUNYAN_T_INT32, "query_state", sqp->sq_state,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+
+ /*
+ * The valid size is anything <= to what the user requested, but at
+ * least svp_log_ack_t bytes large.
+ */
+ if (nop == SVP_R_LOG_ACK) {
+ const char *msg = NULL;
+ if (nsize < sizeof (svp_log_ack_t))
+ msg = "response size too small";
+ else if (nsize > ((svp_log_req_t *)sqp->sq_rdata)->svlr_count)
+ msg = "response size too large";
+ if (msg != NULL) {
+ (void) bunyan_warn(svp_bunyan, msg,
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port",
+ scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version", nvers,
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response_id", resp->svp_id,
+ BUNYAN_T_INT32, "response_size", nsize,
+ BUNYAN_T_INT32, "expected_size",
+ ((svp_log_req_t *)sqp->sq_rdata)->svlr_count,
+ BUNYAN_T_INT32, "query_state", sqp->sq_state,
+ BUNYAN_T_END);
+ return (B_FALSE);
+ }
+ }
+
+ sqp->sq_size = nsize;
+ scp->sc_input.sci_query = sqp;
+ if (nop == SVP_R_VL2_ACK || nop == SVP_R_VL3_ACK ||
+ nop == SVP_R_LOG_RM_ACK) {
+ sqp->sq_wdata = &sqp->sq_wdun;
+ sqp->sq_wsize = sizeof (svp_query_data_t);
+ } else {
+ VERIFY(nop == SVP_R_LOG_ACK);
+ assert(sqp->sq_wdata != NULL);
+ assert(sqp->sq_wsize != 0);
+ }
+
+ return (B_TRUE);
+}
+
+static svp_conn_act_t
+svp_conn_pollin(svp_conn_t *scp)
+{
+ size_t off, total;
+ ssize_t ret;
+ svp_query_t *sqp;
+ uint32_t crc;
+ uint16_t nop;
+
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ /*
+ * No query implies that we're reading in the header and that the offset
+ * is associted with it.
+ */
+ off = scp->sc_input.sci_offset;
+ sqp = scp->sc_input.sci_query;
+ if (scp->sc_input.sci_query == NULL) {
+ svp_req_t *resp = &scp->sc_input.sci_req;
+
+ assert(off < sizeof (svp_req_t));
+
+ do {
+ ret = read(scp->sc_socket,
+ (void *)((uintptr_t)resp + off),
+ sizeof (svp_req_t) - off);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ switch (errno) {
+ case EAGAIN:
+ scp->sc_event.se_events |= POLLIN | POLLRDNORM;
+ return (SVP_RA_NONE);
+ case EIO:
+ case ECONNRESET:
+ return (SVP_RA_ERROR);
+ break;
+ default:
+ libvarpd_panic("unexpeted read errno: %d",
+ errno);
+ }
+ } else if (ret == 0) {
+ /* Try to reconnect to the remote host */
+ return (SVP_RA_ERROR);
+ }
+
+ /* Didn't get all the data we need */
+ if (off + ret < sizeof (svp_req_t)) {
+ scp->sc_input.sci_offset += ret;
+ scp->sc_event.se_events |= POLLIN | POLLRDNORM;
+ return (SVP_RA_NONE);
+ }
+
+ if (svp_conn_pollin_validate(scp) != B_TRUE)
+ return (SVP_RA_ERROR);
+ }
+
+ sqp = scp->sc_input.sci_query;
+ assert(sqp != NULL);
+ sqp->sq_acttime = gethrtime();
+ total = ntohl(scp->sc_input.sci_req.svp_size);
+ do {
+ ret = read(scp->sc_socket,
+ (void *)((uintptr_t)sqp->sq_wdata + off),
+ total - off);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ switch (errno) {
+ case EAGAIN:
+ scp->sc_event.se_events |= POLLIN | POLLRDNORM;
+ return (SVP_RA_NONE);
+ case EIO:
+ case ECONNRESET:
+ return (SVP_RA_ERROR);
+ break;
+ default:
+ libvarpd_panic("unexpeted read errno: %d", errno);
+ }
+ } else if (ret == 0) {
+ /* Try to reconnect to the remote host */
+ return (SVP_RA_ERROR);
+ }
+
+ if (ret + off < total) {
+ scp->sc_input.sci_offset += ret;
+ return (SVP_RA_NONE);
+ }
+
+ nop = ntohs(scp->sc_input.sci_req.svp_op);
+ crc = scp->sc_input.sci_req.svp_crc32;
+ svp_query_crc32(&scp->sc_input.sci_req, sqp->sq_wdata, total);
+ if (crc != scp->sc_input.sci_req.svp_crc32) {
+ (void) bunyan_info(svp_bunyan, "crc32 mismatch",
+ BUNYAN_T_IP, "remote ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "version",
+ ntohs(scp->sc_input.sci_req.svp_ver),
+ BUNYAN_T_INT32, "operation", nop,
+ BUNYAN_T_INT32, "response id",
+ ntohl(scp->sc_input.sci_req.svp_id),
+ BUNYAN_T_INT32, "query state", sqp->sq_state,
+ BUNYAN_T_UINT32, "msg_crc", ntohl(crc),
+ BUNYAN_T_UINT32, "calc_crc",
+ ntohl(scp->sc_input.sci_req.svp_crc32),
+ BUNYAN_T_END);
+ return (SVP_RA_ERROR);
+ }
+ scp->sc_input.sci_query = NULL;
+ scp->sc_input.sci_offset = 0;
+
+ if (nop == SVP_R_VL2_ACK) {
+ svp_vl2_ack_t *sl2a = sqp->sq_wdata;
+ sqp->sq_status = ntohl(sl2a->sl2a_status);
+ } else if (nop == SVP_R_VL3_ACK) {
+ svp_vl3_ack_t *sl3a = sqp->sq_wdata;
+ sqp->sq_status = ntohl(sl3a->sl3a_status);
+ } else if (nop == SVP_R_LOG_ACK) {
+ svp_log_ack_t *svla = sqp->sq_wdata;
+ sqp->sq_status = ntohl(svla->svla_status);
+ } else if (nop == SVP_R_LOG_RM_ACK) {
+ svp_lrm_ack_t *svra = sqp->sq_wdata;
+ sqp->sq_status = ntohl(svra->svra_status);
+ } else {
+ libvarpd_panic("unhandled nop: %d", nop);
+ }
+
+ list_remove(&scp->sc_queries, sqp);
+ mutex_exit(&scp->sc_lock);
+
+ /*
+ * We have to release all of our resources associated with this entry
+ * before we call the callback. After we call it, the memory will be
+ * lost to time.
+ */
+ svp_query_release(sqp);
+ sqp->sq_func(sqp, sqp->sq_arg);
+ mutex_enter(&scp->sc_lock);
+ scp->sc_event.se_events |= POLLIN | POLLRDNORM;
+
+ return (SVP_RA_NONE);
+}
+
+static svp_conn_act_t
+svp_conn_reset(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&scp->sc_lock));
+
+ assert(svp_event_dissociate(&scp->sc_event, scp->sc_socket) ==
+ ENOENT);
+ if (close(scp->sc_socket) != 0)
+ libvarpd_panic("failed to close socket %d: %d", scp->sc_socket,
+ errno);
+ scp->sc_flags &= ~SVP_CF_TEARDOWN;
+ scp->sc_socket = -1;
+ scp->sc_cstate = SVP_CS_INITIAL;
+ scp->sc_input.sci_query = NULL;
+ scp->sc_output.sco_query = NULL;
+
+ svp_remote_reassign(srp, scp);
+
+ return (svp_conn_connect(scp));
+}
+
+/*
+ * This is our general state transition function. We're called here when we want
+ * to advance part of our state machine as well as to re-arm ourselves. We can
+ * also end up here from the standard event loop as a result of having a user
+ * event posted.
+ */
+static void
+svp_conn_handler(port_event_t *pe, void *arg)
+{
+ svp_conn_t *scp = arg;
+ svp_remote_t *srp = scp->sc_remote;
+ svp_conn_act_t ret = SVP_RA_NONE;
+ svp_conn_state_t oldstate;
+
+ mutex_enter(&scp->sc_lock);
+
+ /*
+ * Check if one of our event interrupts is set. An event interrupt, such
+ * as having to be reaped or be torndown is notified by a
+ * PORT_SOURCE_USER event that tries to take care of this. However,
+ * because of the fact that the event loop can be ongoing despite this,
+ * we may get here before the PORT_SOURCE_USER has casued us to get
+ * here. In such a case, if the PORT_SOURCE_USER event is tagged, then
+ * we're going to opt to do nothing here and wait for it to come and
+ * tear us down. That will also indicate to us that we have nothing to
+ * worry about as far as general timing and the like goes.
+ */
+ if ((scp->sc_flags & SVP_CF_UFLAG) != 0 &&
+ (scp->sc_flags & SVP_CF_USER) != 0 &&
+ pe != NULL &&
+ pe->portev_source != PORT_SOURCE_USER) {
+ mutex_exit(&scp->sc_lock);
+ return;
+ }
+
+ if (pe != NULL && pe->portev_source == PORT_SOURCE_USER) {
+ scp->sc_flags &= ~SVP_CF_USER;
+ if ((scp->sc_flags & SVP_CF_UFLAG) == 0) {
+ mutex_exit(&scp->sc_lock);
+ return;
+ }
+ }
+
+ /* Check if this needs to be freed */
+ if (scp->sc_flags & SVP_CF_REAP) {
+ mutex_exit(&scp->sc_lock);
+ svp_conn_destroy(scp);
+ return;
+ }
+
+ /* Check if this needs to be reset */
+ if (scp->sc_flags & SVP_CF_TEARDOWN) {
+ /* Make sure any other users of this are disassociated */
+ ret = SVP_RA_ERROR;
+ goto out;
+ }
+
+ switch (scp->sc_cstate) {
+ case SVP_CS_INITIAL:
+ case SVP_CS_BACKOFF:
+ assert(pe == NULL);
+ ret = svp_conn_connect(scp);
+ break;
+ case SVP_CS_CONNECTING:
+ assert(pe != NULL);
+ ret = svp_conn_poll_connect(pe, scp);
+ break;
+ case SVP_CS_ACTIVE:
+ case SVP_CS_WINDDOWN:
+ assert(pe != NULL);
+ oldstate = scp->sc_cstate;
+ if (pe->portev_events & POLLOUT)
+ ret = svp_conn_pollout(scp);
+ if (ret == SVP_RA_NONE && (pe->portev_events & POLLIN))
+ ret = svp_conn_pollin(scp);
+
+ if (oldstate == SVP_CS_WINDDOWN &&
+ (list_is_empty(&scp->sc_queries) || ret != SVP_RA_NONE)) {
+ ret = SVP_RA_CLEANUP;
+ }
+
+ if (ret == SVP_RA_NONE) {
+ int err;
+ if ((err = svp_event_associate(&scp->sc_event,
+ scp->sc_socket)) != 0) {
+ scp->sc_error = SVP_CE_ASSOCIATE;
+ scp->sc_errno = err;
+ scp->sc_cstate = SVP_CS_ERROR;
+ ret = SVP_RA_DEGRADE;
+ }
+ }
+ break;
+ default:
+ libvarpd_panic("svp_conn_handler encountered unexpected "
+ "state: %d", scp->sc_cstate);
+ }
+out:
+ mutex_exit(&scp->sc_lock);
+
+ if (ret == SVP_RA_NONE)
+ return;
+
+ mutex_enter(&srp->sr_lock);
+ mutex_enter(&scp->sc_lock);
+ if (ret == SVP_RA_ERROR)
+ ret = svp_conn_reset(scp);
+
+ if (ret == SVP_RA_DEGRADE)
+ svp_conn_degrade(scp);
+ if (ret == SVP_RA_RESTORE)
+ svp_conn_restore(scp);
+
+ if (ret == SVP_RA_CLEANUP) {
+ svp_conn_remove(scp);
+ scp->sc_flags |= SVP_CF_REAP;
+ svp_conn_inject(scp);
+ }
+ mutex_exit(&scp->sc_lock);
+ mutex_exit(&srp->sr_lock);
+}
+
+static void
+svp_conn_backtimer(void *arg)
+{
+ svp_conn_t *scp = arg;
+
+ svp_conn_handler(NULL, scp);
+}
+
+/*
+ * This fires every svp_conn_query_timeout seconds. Its purpos is to determine
+ * if we haven't heard back on a request with in svp_conn_query_timeout seconds.
+ * If any of the svp_conn_query_t's that have been started (indicated by
+ * svp_query_t`sq_acttime != -1), and more than svp_conn_query_timeout seconds
+ * have passed, we basically tear this connection down and reassign outstanding
+ * queries.
+ */
+static void
+svp_conn_querytimer(void *arg)
+{
+ int ret;
+ svp_query_t *sqp;
+ svp_conn_t *scp = arg;
+ hrtime_t now = gethrtime();
+
+ mutex_enter(&scp->sc_lock);
+
+ /*
+ * If we're not in the active state, then we don't care about this as
+ * we're already either going to die or we have no connections to worry
+ * about.
+ */
+ if (scp->sc_cstate != SVP_CS_ACTIVE) {
+ mutex_exit(&scp->sc_lock);
+ return;
+ }
+
+ for (sqp = list_head(&scp->sc_queries); sqp != NULL;
+ sqp = list_next(&scp->sc_queries, sqp)) {
+ if (sqp->sq_acttime == -1)
+ continue;
+ if ((now - sqp->sq_acttime) / NANOSEC > svp_conn_query_timeout)
+ break;
+ }
+
+ /* Nothing timed out, we're good here */
+ if (sqp == NULL) {
+ mutex_exit(&scp->sc_lock);
+ return;
+ }
+
+ (void) bunyan_warn(svp_bunyan, "query timed out on connection",
+ BUNYAN_T_IP, "remote_ip", &scp->sc_addr,
+ BUNYAN_T_INT32, "remote_port", scp->sc_remote->sr_rport,
+ BUNYAN_T_INT32, "operation", ntohs(sqp->sq_header.svp_op),
+ BUNYAN_T_END);
+
+ /*
+ * Begin the tear down process for this connect. If we lose the
+ * disassociate, then we don't inject an event. See the big theory
+ * statement in libvarpd_svp.c for more information.
+ */
+ scp->sc_flags |= SVP_CF_TEARDOWN;
+
+ ret = svp_event_dissociate(&scp->sc_event, scp->sc_socket);
+ if (ret == 0)
+ svp_conn_inject(scp);
+ else
+ VERIFY(ret == ENOENT);
+
+ mutex_exit(&scp->sc_lock);
+}
+
+/*
+ * This connection has fallen out of DNS, figure out what we need to do with it.
+ */
+void
+svp_conn_fallout(svp_conn_t *scp)
+{
+ svp_remote_t *srp = scp->sc_remote;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+
+ mutex_enter(&scp->sc_lock);
+ switch (scp->sc_cstate) {
+ case SVP_CS_ERROR:
+ /*
+ * Connection is already inactive, so it's safe to tear down.
+ * Fire it off through the state machine to tear down via the
+ * backoff timer.
+ */
+ svp_conn_remove(scp);
+ scp->sc_flags |= SVP_CF_REAP;
+ svp_conn_inject(scp);
+ break;
+ case SVP_CS_INITIAL:
+ case SVP_CS_BACKOFF:
+ case SVP_CS_CONNECTING:
+ /*
+ * Here, we have something actively going on, so we'll let it be
+ * clean up the next time we hit the event loop by the event
+ * loop itself. As it has no connections, there isn't much to
+ * really do, though we'll take this chance to go ahead and
+ * remove it from the remote.
+ */
+ svp_conn_remove(scp);
+ scp->sc_flags |= SVP_CF_REAP;
+ svp_conn_inject(scp);
+ break;
+ case SVP_CS_ACTIVE:
+ case SVP_CS_WINDDOWN:
+ /*
+ * If there are no outstanding queries, then we should simply
+ * clean this up now,t he same way we would with the others.
+ * Othewrise, as we know the event loop is ongoing, we'll make
+ * sure that these entries get cleaned up once they're done.
+ */
+ scp->sc_cstate = SVP_CS_WINDDOWN;
+ if (list_is_empty(&scp->sc_queries)) {
+ svp_conn_remove(scp);
+ scp->sc_flags |= SVP_CF_REAP;
+ svp_conn_inject(scp);
+ }
+ break;
+ default:
+ libvarpd_panic("svp_conn_fallout encountered"
+ "unkonwn state");
+ }
+ mutex_exit(&scp->sc_lock);
+ mutex_exit(&srp->sr_lock);
+}
+
+int
+svp_conn_create(svp_remote_t *srp, const struct in6_addr *addr)
+{
+ int ret;
+ svp_conn_t *scp;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ scp = umem_zalloc(sizeof (svp_conn_t), UMEM_DEFAULT);
+ if (scp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&scp->sc_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(scp, sizeof (svp_conn_t));
+ return (ret);
+ }
+
+ scp->sc_remote = srp;
+ scp->sc_event.se_func = svp_conn_handler;
+ scp->sc_event.se_arg = scp;
+ scp->sc_btimer.st_func = svp_conn_backtimer;
+ scp->sc_btimer.st_arg = scp;
+ scp->sc_btimer.st_oneshot = B_TRUE;
+ scp->sc_btimer.st_value = 1;
+
+ scp->sc_qtimer.st_func = svp_conn_querytimer;
+ scp->sc_qtimer.st_arg = scp;
+ scp->sc_qtimer.st_oneshot = B_FALSE;
+ scp->sc_qtimer.st_value = svp_conn_query_timeout;
+
+ scp->sc_socket = -1;
+
+ list_create(&scp->sc_queries, sizeof (svp_query_t),
+ offsetof(svp_query_t, sq_lnode));
+ scp->sc_gen = srp->sr_gen;
+ bcopy(addr, &scp->sc_addr, sizeof (struct in6_addr));
+ scp->sc_cstate = SVP_CS_INITIAL;
+ mutex_enter(&scp->sc_lock);
+ svp_conn_add(scp);
+ mutex_exit(&scp->sc_lock);
+
+ /* Now that we're locked and loaded, add our timers */
+ svp_timer_add(&scp->sc_qtimer);
+ svp_timer_add(&scp->sc_btimer);
+
+ return (0);
+}
+
+/*
+ * At the time of calling, the entry has been removed from all lists. In
+ * addition, the entries state should be SVP_CS_ERROR, therefore, we know that
+ * the fd should not be associated with the event loop. We'll double check that
+ * just in case. We should also have already been removed from the remote's
+ * list.
+ */
+void
+svp_conn_destroy(svp_conn_t *scp)
+{
+ int ret;
+
+ mutex_enter(&scp->sc_lock);
+ if (scp->sc_cstate != SVP_CS_ERROR)
+ libvarpd_panic("asked to tear down an active connection");
+ if (scp->sc_flags & SVP_CF_ADDED)
+ libvarpd_panic("asked to remove a connection still in "
+ "the remote list\n");
+ if (!list_is_empty(&scp->sc_queries))
+ libvarpd_panic("asked to remove a connection with non-empty "
+ "query list");
+
+ if ((ret = svp_event_dissociate(&scp->sc_event, scp->sc_socket)) !=
+ ENOENT) {
+ libvarpd_panic("dissociate failed or was actually "
+ "associated: %d", ret);
+ }
+ mutex_exit(&scp->sc_lock);
+
+ /* Verify our timers are killed */
+ svp_timer_remove(&scp->sc_btimer);
+ svp_timer_remove(&scp->sc_qtimer);
+
+ if (scp->sc_socket != -1 && close(scp->sc_socket) != 0)
+ libvarpd_panic("failed to close svp_conn_t`scp_socket fd "
+ "%d: %d", scp->sc_socket, errno);
+
+ list_destroy(&scp->sc_queries);
+ umem_free(scp, sizeof (svp_conn_t));
+}
+
+void
+svp_conn_queue(svp_conn_t *scp, svp_query_t *sqp)
+{
+ assert(MUTEX_HELD(&scp->sc_lock));
+ assert(scp->sc_cstate == SVP_CS_ACTIVE);
+
+ sqp->sq_acttime = -1;
+ list_insert_tail(&scp->sc_queries, sqp);
+ if (!(scp->sc_event.se_events & POLLOUT)) {
+ scp->sc_event.se_events |= POLLOUT;
+ /*
+ * If this becomes frequent, we should instead give up on this
+ * set of connections instead of aborting.
+ */
+ if (svp_event_associate(&scp->sc_event, scp->sc_socket) != 0)
+ libvarpd_panic("svp_event_associate failed somehow");
+ }
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_crc.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_crc.c
new file mode 100644
index 0000000000..ade47ff998
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_crc.c
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * Perform standard crc32 functions.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ *
+ * Really, this should just be a libcrc.
+ */
+
+#include <sys/crc32.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <libvarpd_svp.h>
+
+static uint32_t svp_crc32_tab[] = { CRC32_TABLE };
+
+static uint32_t
+svp_crc32(uint32_t old, const uint8_t *buf, size_t len)
+{
+ uint32_t out;
+
+ CRC32(out, buf, len, old, svp_crc32_tab);
+ return (out);
+}
+
+void
+svp_query_crc32(svp_req_t *shp, void *buf, size_t data)
+{
+ uint32_t crc = -1U;
+
+ shp->svp_crc32 = 0;
+ crc = svp_crc32(crc, (uint8_t *)shp, sizeof (svp_req_t));
+ crc = svp_crc32(crc, buf, data);
+ crc = ~crc;
+ shp->svp_crc32 = htonl(crc);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_host.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_host.c
new file mode 100644
index 0000000000..e91cc30e9d
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_host.c
@@ -0,0 +1,171 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * DNS Host-name related functions.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <thread.h>
+#include <synch.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <libvarpd_svp.h>
+
+int svp_host_nthreads = 8;
+
+static mutex_t svp_host_lock = ERRORCHECKMUTEX;
+static cond_t svp_host_cv = DEFAULTCV;
+static svp_remote_t *svp_host_head;
+
+/* ARGSUSED */
+static void *
+svp_host_loop(void *unused)
+{
+ for (;;) {
+ int err;
+ svp_remote_t *srp;
+ struct addrinfo *addrs;
+
+ mutex_enter(&svp_host_lock);
+ while (svp_host_head == NULL)
+ (void) cond_wait(&svp_host_cv, &svp_host_lock);
+ srp = svp_host_head;
+ svp_host_head = srp->sr_nexthost;
+ if (svp_host_head != NULL)
+ (void) cond_signal(&svp_host_cv);
+ mutex_exit(&svp_host_lock);
+
+ mutex_enter(&srp->sr_lock);
+ assert(srp->sr_state & SVP_RS_LOOKUP_SCHEDULED);
+ srp->sr_state &= ~SVP_RS_LOOKUP_SCHEDULED;
+ if (srp->sr_state & SVP_RS_LOOKUP_INPROGRESS) {
+ mutex_exit(&srp->sr_lock);
+ continue;
+ }
+ srp->sr_state |= SVP_RS_LOOKUP_INPROGRESS;
+ mutex_exit(&srp->sr_lock);
+
+ for (;;) {
+ err = getaddrinfo(srp->sr_hostname, NULL, NULL, &addrs);
+ if (err == 0)
+ break;
+ if (err != 0) {
+ switch (err) {
+ case EAI_ADDRFAMILY:
+ case EAI_BADFLAGS:
+ case EAI_FAMILY:
+ case EAI_SERVICE:
+ case EAI_SOCKTYPE:
+ case EAI_OVERFLOW:
+ default:
+ libvarpd_panic("unexpected getaddrinfo "
+ "failure: %d", err);
+ break;
+ case EAI_AGAIN:
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ continue;
+ case EAI_FAIL:
+ case EAI_NODATA:
+ case EAI_NONAME:
+ /*
+ * At this point in time we have
+ * something which isn't very good. This
+ * may have been a typo or something may
+ * have been destroyed. We should go
+ * ahead and degrade this overall
+ * instance, because we're not going to
+ * make much forward progress... It'd be
+ * great if we could actually issue more
+ * of an EREPORT to describe what
+ * happened, some day.
+ */
+ mutex_enter(&srp->sr_lock);
+ svp_remote_degrade(srp,
+ SVP_RD_DNS_FAIL);
+ mutex_exit(&srp->sr_lock);
+ break;
+ }
+ }
+ break;
+ }
+
+ if (err == 0) {
+ /*
+ * We've successfully resolved something, mark this
+ * degredation over for now.
+ */
+ mutex_enter(&srp->sr_lock);
+ svp_remote_restore(srp, SVP_RD_DNS_FAIL);
+ mutex_exit(&srp->sr_lock);
+ svp_remote_resolved(srp, addrs);
+ }
+
+ mutex_enter(&srp->sr_lock);
+ srp->sr_state &= ~SVP_RS_LOOKUP_INPROGRESS;
+ (void) cond_broadcast(&srp->sr_cond);
+ mutex_exit(&srp->sr_lock);
+ }
+
+ /* LINTED: E_STMT_NOT_REACHED */
+ return (NULL);
+}
+
+void
+svp_host_queue(svp_remote_t *srp)
+{
+ svp_remote_t *s;
+ mutex_enter(&svp_host_lock);
+ mutex_enter(&srp->sr_lock);
+ if (srp->sr_state & SVP_RS_LOOKUP_SCHEDULED) {
+ mutex_exit(&srp->sr_lock);
+ mutex_exit(&svp_host_lock);
+ return;
+ }
+ srp->sr_state |= SVP_RS_LOOKUP_SCHEDULED;
+ s = svp_host_head;
+ while (s != NULL && s->sr_nexthost != NULL)
+ s = s->sr_nexthost;
+ if (s == NULL) {
+ assert(s == svp_host_head);
+ svp_host_head = srp;
+ } else {
+ s->sr_nexthost = srp;
+ }
+ srp->sr_nexthost = NULL;
+ (void) cond_signal(&svp_host_cv);
+ mutex_exit(&srp->sr_lock);
+ mutex_exit(&svp_host_lock);
+}
+
+int
+svp_host_init(void)
+{
+ int i;
+
+ for (i = 0; i < svp_host_nthreads; i++) {
+ if (thr_create(NULL, 0, svp_host_loop, NULL,
+ THR_DETACHED | THR_DAEMON, NULL) != 0)
+ return (errno);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_loop.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_loop.c
new file mode 100644
index 0000000000..18a79b9dff
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_loop.c
@@ -0,0 +1,210 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Event loop mechanism for our backend.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+#include <unistd.h>
+#include <thread.h>
+#include <port.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <umem.h>
+
+#include <libvarpd_svp.h>
+
+typedef struct svp_event_loop {
+ int sel_port; /* RO */
+ int sel_nthread; /* RO */
+ thread_t *sel_threads; /* RO */
+ boolean_t sel_stop; /* svp_elock */
+ timer_t sel_hosttimer;
+} svp_event_loop_t;
+
+static svp_event_loop_t svp_event;
+static mutex_t svp_elock = ERRORCHECKMUTEX;
+
+/* ARGSUSED */
+static void *
+svp_event_thr(void *arg)
+{
+ for (;;) {
+ int ret;
+ port_event_t pe;
+ svp_event_t *sep;
+
+ mutex_enter(&svp_elock);
+ if (svp_event.sel_stop == B_TRUE) {
+ mutex_exit(&svp_elock);
+ break;
+ }
+ mutex_exit(&svp_elock);
+
+ ret = port_get(svp_event.sel_port, &pe, NULL);
+ if (ret != 0) {
+ switch (errno) {
+ case EFAULT:
+ case EBADF:
+ case EINVAL:
+ libvarpd_panic("unexpected port_get errno: %d",
+ errno);
+ default:
+ break;
+ }
+ }
+
+ if (pe.portev_user == NULL)
+ libvarpd_panic("received event (%p) without "
+ "protev_user set", &pe);
+ sep = (svp_event_t *)pe.portev_user;
+ sep->se_func(&pe, sep->se_arg);
+ }
+
+ return (NULL);
+}
+
+int
+svp_event_associate(svp_event_t *sep, int fd)
+{
+ int ret;
+
+ ret = port_associate(svp_event.sel_port, PORT_SOURCE_FD, fd,
+ sep->se_events, sep);
+ if (ret != 0) {
+ switch (errno) {
+ case EBADF:
+ case EBADFD:
+ case EINVAL:
+ case EAGAIN:
+ libvarpd_panic("unexpected port_associate error: %d",
+ errno);
+ default:
+ ret = errno;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/* ARGSUSED */
+int
+svp_event_dissociate(svp_event_t *sep, int fd)
+{
+ int ret;
+
+ ret = port_dissociate(svp_event.sel_port, PORT_SOURCE_FD, fd);
+ if (ret != 0) {
+ if (errno != ENOENT)
+ libvarpd_panic("unexpected port_dissociate error: %d",
+ errno);
+ ret = errno;
+ }
+ return (ret);
+}
+
+int
+svp_event_inject(svp_event_t *user)
+{
+ return (port_send(svp_event.sel_port, 0, user));
+}
+
+int
+svp_event_timer_init(svp_event_t *sep)
+{
+ port_notify_t pn;
+ struct sigevent evp;
+ struct itimerspec ts;
+
+ pn.portnfy_port = svp_event.sel_port;
+ pn.portnfy_user = sep;
+ evp.sigev_notify = SIGEV_PORT;
+ evp.sigev_value.sival_ptr = &pn;
+
+ if (timer_create(CLOCK_REALTIME, &evp, &svp_event.sel_hosttimer) != 0)
+ return (errno);
+
+ ts.it_value.tv_sec = svp_tickrate;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = svp_tickrate;
+ ts.it_interval.tv_nsec = 0;
+
+ if (timer_settime(svp_event.sel_hosttimer, TIMER_RELTIME, &ts,
+ NULL) != 0) {
+ int ret = errno;
+ (void) timer_delete(svp_event.sel_hosttimer);
+ return (ret);
+ }
+
+ return (0);
+}
+
+int
+svp_event_init(void)
+{
+ long i, ncpus;
+
+ svp_event.sel_port = port_create();
+ if (svp_event.sel_port == -1)
+ return (errno);
+
+ ncpus = sysconf(_SC_NPROCESSORS_ONLN) * 2 + 1;
+ if (ncpus <= 0)
+ libvarpd_panic("sysconf for nprocs failed... %d/%d",
+ ncpus, errno);
+
+ svp_event.sel_threads = umem_alloc(sizeof (thread_t) * ncpus,
+ UMEM_DEFAULT);
+ if (svp_event.sel_threads == NULL) {
+ int ret = errno;
+ (void) timer_delete(svp_event.sel_hosttimer);
+ (void) close(svp_event.sel_port);
+ svp_event.sel_port = -1;
+ return (ret);
+ }
+
+ for (i = 0; i < ncpus; i++) {
+ int ret;
+ thread_t *thr = &svp_event.sel_threads[i];
+
+ ret = thr_create(NULL, 0, svp_event_thr, NULL,
+ THR_DETACHED | THR_DAEMON, thr);
+ if (ret != 0) {
+ ret = errno;
+ (void) timer_delete(svp_event.sel_hosttimer);
+ (void) close(svp_event.sel_port);
+ svp_event.sel_port = -1;
+ return (errno);
+ }
+ }
+
+ return (0);
+}
+
+void
+svp_event_fini(void)
+{
+ mutex_enter(&svp_elock);
+ svp_event.sel_stop = B_TRUE;
+ mutex_exit(&svp_elock);
+
+ (void) timer_delete(svp_event.sel_hosttimer);
+ (void) close(svp_event.sel_port);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h b/usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h
new file mode 100644
index 0000000000..16dbdbec05
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_prot.h
@@ -0,0 +1,236 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_SVP_PROT_H
+#define _LIBVARPD_SVP_PROT_H
+
+/*
+ * SVP protocol Definitions
+ */
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <sys/ethernet.h>
+#include <netinet/in.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SDC VXLAN Protocol Definitions
+ */
+
+#define SVP_VERSION_ONE 1
+#define SVP_CURRENT_VERSION SVP_VERSION_ONE
+
+typedef struct svp_req {
+ uint16_t svp_ver;
+ uint16_t svp_op;
+ uint32_t svp_size;
+ uint32_t svp_id;
+ uint32_t svp_crc32;
+} svp_req_t;
+
+typedef enum svp_op {
+ SVP_R_UNKNOWN = 0x00,
+ SVP_R_PING = 0x01,
+ SVP_R_PONG = 0x02,
+ SVP_R_VL2_REQ = 0x03,
+ SVP_R_VL2_ACK = 0x04,
+ SVP_R_VL3_REQ = 0x05,
+ SVP_R_VL3_ACK = 0x06,
+ SVP_R_BULK_REQ = 0x07,
+ SVP_R_BULK_ACK = 0x08,
+ SVP_R_LOG_REQ = 0x09,
+ SVP_R_LOG_ACK = 0x0A,
+ SVP_R_LOG_RM = 0x0B,
+ SVP_R_LOG_RM_ACK = 0x0C,
+ SVP_R_SHOOTDOWN = 0x0D
+} svp_op_t;
+
+typedef enum svp_status {
+ SVP_S_OK = 0x00, /* Everything OK */
+ SVP_S_FATAL = 0x01, /* Fatal error, close connection */
+ SVP_S_NOTFOUND = 0x02, /* Entry not found */
+ SVP_S_BADL3TYPE = 0x03, /* Unknown svp_vl3_type_t */
+ SVP_S_BADBULK = 0x04 /* Unknown svp_bulk_type_t */
+} svp_status_t;
+
+/*
+ * A client issues the SVP_R_VL2_REQ whenever it needs to perform a VLS->UL3
+ * lookup. Requests have the following structure:
+ */
+typedef struct svp_vl2_req {
+ uint8_t sl2r_mac[ETHERADDRL];
+ uint8_t sl2r_pad[2];
+ uint32_t sl2r_vnetid;
+} svp_vl2_req_t;
+
+/*
+ * This is the message a server uses to reply to the SVP_R_VL2_REQ. If the
+ * destination on the underlay is an IPv4 address, it should be encoded as an
+ * IPv4-mapped IPv6 address.
+ */
+typedef struct svp_vl2_ack {
+ uint16_t sl2a_status;
+ uint16_t sl2a_port;
+ uint8_t sl2a_addr[16];
+} svp_vl2_ack_t;
+
+
+/*
+ * A client issues the SVP_R_VL3_REQ request whenever it needs to perform a
+ * VL3->VL2 lookup. Note, that this also implicitly performs a VL2->UL3 lookup
+ * as well. The sl3r_type member is used to indicate the kind of lookup type
+ * that we're performing, eg. is it a L3 or L2.
+ */
+typedef enum svp_vl3_type {
+ SVP_VL3_IP = 0x01,
+ SVP_VL3_IPV6 = 0x02
+} svp_vl3_type_t;
+
+typedef struct svp_vl3_req {
+ uint8_t sl3r_ip[16];
+ uint32_t sl3r_type;
+ uint32_t sl3r_vnetid;
+} svp_vl3_req_t;
+
+/*
+ * This response, corresponding to the SVP_R_VL3_ACK, includes an answer to both
+ * the VL3->VL2 and the VL2->UL3 requests.
+ */
+typedef struct svp_vl3_ack {
+ uint32_t sl3a_status;
+ uint8_t sl3a_mac[ETHERADDRL];
+ uint16_t sl3a_uport;
+ uint8_t sl3a_uip[16];
+} svp_vl3_ack_t;
+
+/*
+ * SVP_R_BULK_REQ requests a bulk dump of data. Currently we have two kinds of
+ * data tables that we need to dump: VL3->VL2 mappings and VL2->UL3 mappings.
+ * The kind that we want is indicated using the svbr_type member.
+ */
+typedef enum svp_bulk_type {
+ SVP_BULK_VL2 = 0x01,
+ SVP_BULK_VL3 = 0x02
+} svp_bulk_type_t;
+
+typedef struct svp_bulk_req {
+ uint32_t svbr_type;
+} svp_bulk_req_t;
+
+/*
+ * When replying to a bulk request (SVP_R_BULK_ACK), data is streamed back
+ * across. The format of the data is currently undefined and as we work on the
+ * system, we'll get a better understanding of what this should look like. A
+ * client may need to stream such a request to disk, or the format will need to
+ * be in a streamable format that allows the client to construct data.
+ */
+typedef struct svp_bulk_ack {
+ uint32_t svba_status;
+ uint32_t svba_type;
+ uint8_t svba_data[];
+} svp_bulk_ack_t;
+
+/*
+ * SVP_R_LOG_REQ requests a log entries from the specified log from the server.
+ * The total number of bytes that the user is ready to receive is in svlr_count.
+ * However, the server should not block for data if none is available and thus
+ * may return less than svlr_count bytes back. We identify the IP address of the
+ * underlay to use here explicitly.
+ */
+typedef struct svp_log_req {
+ uint32_t svlr_count;
+ uint8_t svlr_ip[16];
+} svp_log_req_t;
+
+/*
+ * The server replies to a log request by sending a series of log entries.
+ * These log entries may be a mixture of both vl2 and vl3 records. The reply is
+ * a stream of bytes after the status message whose length is determined baseed
+ * on the header itself. Each entry begins with a uint32_t that describes its
+ * type and then is followed by the remaining data payload. The next entry
+ * follows immediately which again begins with the uint32_t word that describes
+ * what it should be.
+ */
+typedef enum svp_log_type {
+ SVP_LOG_VL2 = 0x01,
+ SVP_LOG_VL3 = 0x02
+} svp_log_type_t;
+
+typedef struct svp_log_vl2 {
+ uint32_t svl2_type; /* Should be SVP_LOG_VL2 */
+ uint8_t svl2_id[16]; /* 16-byte UUID */
+ uint8_t svl2_mac[ETHERADDRL];
+ uint8_t svl2_pad[2];
+ uint32_t svl2_vnetid;
+} svp_log_vl2_t;
+
+typedef struct svp_log_vl3 {
+ uint32_t svl3_type; /* Should be SVP_LOG_VL3 */
+ uint8_t svl3_id[16]; /* 16-byte UUID */
+ uint8_t svl3_ip[16];
+ uint8_t svl3_pad[2];
+ uint16_t svl3_vlan;
+ uint32_t svl3_vnetid;
+} svp_log_vl3_t;
+
+typedef struct svp_log_ack {
+ uint32_t svla_status;
+ uint8_t svla_data[];
+} svp_log_ack_t;
+
+/*
+ * SVP_R_LOG_RM is used after the client successfully processes a series of the
+ * log stream. It replies to tell the server that it can remove those IDs from
+ * processing. The IDs used are the same IDs that were in the individual
+ * SVP_R_LOG_ACK entries.
+ */
+typedef struct svp_lrm_req {
+ uint32_t svrr_count;
+ uint8_t svrr_ids[];
+} svp_lrm_req_t;
+
+/*
+ * SVP_R_LOG_RM_ACK is used to indicate that a log entry has been successfully
+ * deleted and at this point it makes sense to go and ask for another
+ * SVP_R_LOG_REQ.
+ */
+typedef struct svp_lrm_ack {
+ uint32_t svra_status;
+} svp_lrm_ack_t;
+
+/*
+ * A shootdown (SVP_R_SHOOTDOWN) is used by a CN to reply to another CN that it
+ * sent an invalid entry that could not be processed. This should be a
+ * relatively infrequent occurrence. Unlike the rest of the messages, there is
+ * no reply to it. It's a single request to try and help get us out there. When
+ * a node receives this, it will issue a conditional revocation ioctl, that
+ * removes the entry if and only if, it matches the IP. That way if we've
+ * already gotten an updated entry for this, we don't remove it again.
+ */
+typedef struct svp_shootdown {
+ uint8_t svsd_mac[ETHERADDRL];
+ uint8_t svsd_pad[2];
+ uint32_t svsd_vnetid;
+} svp_shootdown_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_SVP_PROT_H */
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c
new file mode 100644
index 0000000000..8d482e4a12
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_remote.c
@@ -0,0 +1,821 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Remote backend management
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+#include <umem.h>
+#include <strings.h>
+#include <string.h>
+#include <stddef.h>
+#include <thread.h>
+#include <synch.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <libidspace.h>
+
+#include <libvarpd_provider.h>
+#include <libvarpd_svp.h>
+
+typedef struct svp_shoot_vl3 {
+ svp_query_t ssv_query;
+ struct sockaddr_in6 ssv_sock;
+ svp_log_vl3_t *ssv_vl3;
+ svp_sdlog_t *ssv_log;
+} svp_shoot_vl3_t;
+
+static mutex_t svp_remote_lock = ERRORCHECKMUTEX;
+static avl_tree_t svp_remote_tree;
+static svp_timer_t svp_dns_timer;
+static id_space_t *svp_idspace;
+static int svp_dns_timer_rate = 30; /* seconds */
+
+static void
+svp_remote_mkfmamsg(svp_remote_t *srp, svp_degrade_state_t state, char *buf,
+ size_t buflen)
+{
+ switch (state) {
+ case SVP_RD_DNS_FAIL:
+ (void) snprintf(buf, buflen, "failed to resolve or find "
+ "entries for hostname %s", srp->sr_hostname);
+ break;
+ case SVP_RD_REMOTE_FAIL:
+ (void) snprintf(buf, buflen, "cannot reach any remote peers");
+ break;
+ default:
+ (void) snprintf(buf, buflen, "unkonwn error state: %d", state);
+ }
+}
+
+static int
+svp_remote_comparator(const void *l, const void *r)
+{
+ int ret;
+ const svp_remote_t *lr = l, *rr = r;
+
+ ret = strcmp(lr->sr_hostname, rr->sr_hostname);
+ if (ret > 0)
+ return (1);
+ else if (ret < 0)
+ return (-1);
+
+ if (lr->sr_rport > rr->sr_rport)
+ return (1);
+ else if (lr->sr_rport < rr->sr_rport)
+ return (-1);
+
+ return (memcmp(&lr->sr_uip, &rr->sr_uip, sizeof (struct in6_addr)));
+}
+
+void
+svp_query_release(svp_query_t *sqp)
+{
+ id_free(svp_idspace, sqp->sq_header.svp_id);
+}
+
+static void
+svp_remote_destroy(svp_remote_t *srp)
+{
+ size_t len;
+
+ /*
+ * Clean up any unrelated DNS information. At this point we know that
+ * we're not in the remote tree. That means, that svp_remote_dns_timer
+ * cannot queue us. However, if any of our DNS related state flags are
+ * set, we have to hang out.
+ */
+ mutex_enter(&srp->sr_lock);
+ while (srp->sr_state &
+ (SVP_RS_LOOKUP_SCHEDULED | SVP_RS_LOOKUP_INPROGRESS)) {
+ (void) cond_wait(&srp->sr_cond, &srp->sr_lock);
+ }
+ mutex_exit(&srp->sr_lock);
+ svp_shootdown_fini(srp);
+
+ if (cond_destroy(&srp->sr_cond) != 0)
+ libvarpd_panic("failed to destroy cond sr_cond");
+
+ if (mutex_destroy(&srp->sr_lock) != 0)
+ libvarpd_panic("failed to destroy mutex sr_lock");
+
+ if (srp->sr_addrinfo != NULL)
+ freeaddrinfo(srp->sr_addrinfo);
+ len = strlen(srp->sr_hostname) + 1;
+ umem_free(srp->sr_hostname, len);
+ umem_free(srp, sizeof (svp_remote_t));
+}
+
+static int
+svp_remote_create(const char *host, uint16_t port, struct in6_addr *uip,
+ svp_remote_t **outp)
+{
+ size_t hlen;
+ svp_remote_t *remote;
+
+ assert(MUTEX_HELD(&svp_remote_lock));
+
+ remote = umem_zalloc(sizeof (svp_remote_t), UMEM_DEFAULT);
+ if (remote == NULL) {
+ mutex_exit(&svp_remote_lock);
+ return (ENOMEM);
+ }
+
+ if (svp_shootdown_init(remote) != 0) {
+ umem_free(remote, sizeof (svp_remote_t));
+ mutex_exit(&svp_remote_lock);
+ return (ENOMEM);
+ }
+
+ hlen = strlen(host) + 1;
+ remote->sr_hostname = umem_alloc(hlen, UMEM_DEFAULT);
+ if (remote->sr_hostname == NULL) {
+ svp_shootdown_fini(remote);
+ umem_free(remote, sizeof (svp_remote_t));
+ mutex_exit(&svp_remote_lock);
+ return (ENOMEM);
+ }
+ remote->sr_rport = port;
+ if (mutex_init(&remote->sr_lock,
+ USYNC_THREAD | LOCK_ERRORCHECK, NULL) != 0)
+ libvarpd_panic("failed to create mutex sr_lock");
+ if (cond_init(&remote->sr_cond, USYNC_PROCESS, NULL) != 0)
+ libvarpd_panic("failed to create cond sr_cond");
+ list_create(&remote->sr_conns, sizeof (svp_conn_t),
+ offsetof(svp_conn_t, sc_rlist));
+ avl_create(&remote->sr_tree, svp_comparator, sizeof (svp_t),
+ offsetof(svp_t, svp_rlink));
+ (void) strlcpy(remote->sr_hostname, host, hlen);
+ remote->sr_count = 1;
+ remote->sr_uip = *uip;
+
+ svp_shootdown_start(remote);
+
+ *outp = remote;
+ return (0);
+}
+
+int
+svp_remote_find(char *host, uint16_t port, struct in6_addr *uip,
+ svp_remote_t **outp)
+{
+ int ret;
+ svp_remote_t lookup, *remote;
+
+ lookup.sr_hostname = host;
+ lookup.sr_rport = port;
+ lookup.sr_uip = *uip;
+ mutex_enter(&svp_remote_lock);
+ remote = avl_find(&svp_remote_tree, &lookup, NULL);
+ if (remote != NULL) {
+ assert(remote->sr_count > 0);
+ remote->sr_count++;
+ *outp = remote;
+ mutex_exit(&svp_remote_lock);
+ return (0);
+ }
+
+ if ((ret = svp_remote_create(host, port, uip, outp)) != 0) {
+ mutex_exit(&svp_remote_lock);
+ return (ret);
+ }
+
+ avl_add(&svp_remote_tree, *outp);
+ mutex_exit(&svp_remote_lock);
+
+ /* Make sure DNS is up to date */
+ svp_host_queue(*outp);
+
+ return (0);
+}
+
+void
+svp_remote_release(svp_remote_t *srp)
+{
+ mutex_enter(&svp_remote_lock);
+ mutex_enter(&srp->sr_lock);
+ srp->sr_count--;
+ if (srp->sr_count != 0) {
+ mutex_exit(&srp->sr_lock);
+ mutex_exit(&svp_remote_lock);
+ return;
+ }
+ mutex_exit(&srp->sr_lock);
+
+ avl_remove(&svp_remote_tree, srp);
+ mutex_exit(&svp_remote_lock);
+ svp_remote_destroy(srp);
+}
+
+int
+svp_remote_attach(svp_remote_t *srp, svp_t *svp)
+{
+ svp_t check;
+ avl_index_t where;
+
+ mutex_enter(&srp->sr_lock);
+ if (svp->svp_remote != NULL)
+ libvarpd_panic("failed to create mutex sr_lock");
+
+ /*
+ * We require everything except shootdowns
+ */
+ if (svp->svp_cb.scb_vl2_lookup == NULL)
+ libvarpd_panic("missing callback scb_vl2_lookup");
+ if (svp->svp_cb.scb_vl3_lookup == NULL)
+ libvarpd_panic("missing callback scb_vl3_lookup");
+ if (svp->svp_cb.scb_vl2_invalidate == NULL)
+ libvarpd_panic("missing callback scb_vl2_invalidate");
+ if (svp->svp_cb.scb_vl3_inject == NULL)
+ libvarpd_panic("missing callback scb_vl3_inject");
+
+ check.svp_vid = svp->svp_vid;
+ if (avl_find(&srp->sr_tree, &check, &where) != NULL)
+ libvarpd_panic("found duplicate entry with vid %ld",
+ svp->svp_vid);
+ avl_insert(&srp->sr_tree, svp, where);
+ svp->svp_remote = srp;
+ mutex_exit(&srp->sr_lock);
+
+ return (0);
+}
+
+void
+svp_remote_detach(svp_t *svp)
+{
+ svp_t *lookup;
+ svp_remote_t *srp = svp->svp_remote;
+
+ if (srp == NULL)
+ libvarpd_panic("trying to detach remote when none exists");
+
+ mutex_enter(&srp->sr_lock);
+ lookup = avl_find(&srp->sr_tree, svp, NULL);
+ if (lookup == NULL || lookup != svp)
+ libvarpd_panic("inconsitent remote avl tree...");
+ avl_remove(&srp->sr_tree, svp);
+ svp->svp_remote = NULL;
+ mutex_exit(&srp->sr_lock);
+ svp_remote_release(srp);
+}
+
+/*
+ * Walk the list of connections and find the first one that's available, the
+ * move it to the back of the list so it's less likely to be used again.
+ */
+static boolean_t
+svp_remote_conn_queue(svp_remote_t *srp, svp_query_t *sqp)
+{
+ svp_conn_t *scp;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ for (scp = list_head(&srp->sr_conns); scp != NULL;
+ scp = list_next(&srp->sr_conns, scp)) {
+ mutex_enter(&scp->sc_lock);
+ if (scp->sc_cstate != SVP_CS_ACTIVE) {
+ mutex_exit(&scp->sc_lock);
+ continue;
+ }
+ svp_conn_queue(scp, sqp);
+ mutex_exit(&scp->sc_lock);
+ list_remove(&srp->sr_conns, scp);
+ list_insert_tail(&srp->sr_conns, scp);
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+static void
+svp_remote_vl2_lookup_cb(svp_query_t *sqp, void *arg)
+{
+ svp_t *svp = sqp->sq_svp;
+ svp_vl2_ack_t *vl2a = (svp_vl2_ack_t *)sqp->sq_wdata;
+
+ if (sqp->sq_status == SVP_S_OK)
+ svp->svp_cb.scb_vl2_lookup(svp, sqp->sq_status,
+ (struct in6_addr *)vl2a->sl2a_addr, ntohs(vl2a->sl2a_port),
+ arg);
+ else
+ svp->svp_cb.scb_vl2_lookup(svp, sqp->sq_status, NULL, 0, arg);
+}
+
+void
+svp_remote_vl2_lookup(svp_t *svp, svp_query_t *sqp, const uint8_t *mac,
+ void *arg)
+{
+ svp_remote_t *srp;
+ svp_vl2_req_t *vl2r = &sqp->sq_rdun.sqd_vl2r;
+
+ srp = svp->svp_remote;
+ sqp->sq_func = svp_remote_vl2_lookup_cb;
+ sqp->sq_arg = arg;
+ sqp->sq_svp = svp;
+ sqp->sq_state = SVP_QUERY_INIT;
+ sqp->sq_header.svp_ver = htons(SVP_CURRENT_VERSION);
+ sqp->sq_header.svp_op = htons(SVP_R_VL2_REQ);
+ sqp->sq_header.svp_size = htonl(sizeof (svp_vl2_req_t));
+ sqp->sq_header.svp_id = id_alloc(svp_idspace);
+ if (sqp->sq_header.svp_id == (id_t)-1)
+ libvarpd_panic("failed to allcoate from svp_idspace: %d",
+ errno);
+ sqp->sq_header.svp_crc32 = htonl(0);
+ sqp->sq_rdata = vl2r;
+ sqp->sq_rsize = sizeof (svp_vl2_req_t);
+ sqp->sq_wdata = NULL;
+ sqp->sq_wsize = 0;
+
+ bcopy(mac, vl2r->sl2r_mac, ETHERADDRL);
+ vl2r->sl2r_vnetid = ntohl(svp->svp_vid);
+
+ mutex_enter(&srp->sr_lock);
+ if (svp_remote_conn_queue(srp, sqp) == B_FALSE)
+ svp->svp_cb.scb_vl2_lookup(svp, SVP_S_FATAL, NULL, NULL, arg);
+ mutex_exit(&srp->sr_lock);
+}
+
+static void
+svp_remote_vl3_lookup_cb(svp_query_t *sqp, void *arg)
+{
+ svp_t *svp = sqp->sq_svp;
+ svp_vl3_ack_t *vl3a = (svp_vl3_ack_t *)sqp->sq_wdata;
+
+ if (sqp->sq_status == SVP_S_OK)
+ svp->svp_cb.scb_vl3_lookup(svp, sqp->sq_status, vl3a->sl3a_mac,
+ (struct in6_addr *)vl3a->sl3a_uip, ntohs(vl3a->sl3a_uport),
+ arg);
+ else
+ svp->svp_cb.scb_vl3_lookup(svp, sqp->sq_status, NULL, NULL, 0,
+ arg);
+}
+
+static void
+svp_remote_vl3_common(svp_remote_t *srp, svp_query_t *sqp,
+ const struct sockaddr *addr, svp_query_f func, void *arg, uint32_t vid)
+{
+ svp_vl3_req_t *vl3r = &sqp->sq_rdun.sdq_vl3r;
+
+ if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
+ libvarpd_panic("unexpected sa_family for the vl3 lookup");
+
+ sqp->sq_func = func;
+ sqp->sq_arg = arg;
+ sqp->sq_state = SVP_QUERY_INIT;
+ sqp->sq_header.svp_ver = htons(SVP_CURRENT_VERSION);
+ sqp->sq_header.svp_op = htons(SVP_R_VL3_REQ);
+ sqp->sq_header.svp_size = htonl(sizeof (svp_vl3_req_t));
+ sqp->sq_header.svp_id = id_alloc(svp_idspace);
+ if (sqp->sq_header.svp_id == (id_t)-1)
+ libvarpd_panic("failed to allcoate from svp_idspace: %d",
+ errno);
+ sqp->sq_header.svp_crc32 = htonl(0);
+ sqp->sq_rdata = vl3r;
+ sqp->sq_rsize = sizeof (svp_vl3_req_t);
+ sqp->sq_wdata = NULL;
+ sqp->sq_wsize = 0;
+
+ if (addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)addr;
+ vl3r->sl3r_type = htonl(SVP_VL3_IPV6);
+ bcopy(&s6->sin6_addr, vl3r->sl3r_ip,
+ sizeof (struct in6_addr));
+ } else {
+ struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
+ struct in6_addr v6;
+
+ vl3r->sl3r_type = htonl(SVP_VL3_IP);
+ IN6_INADDR_TO_V4MAPPED(&s4->sin_addr, &v6);
+ bcopy(&v6, vl3r->sl3r_ip, sizeof (struct in6_addr));
+ }
+ vl3r->sl3r_vnetid = htonl(vid);
+
+ mutex_enter(&srp->sr_lock);
+ if (svp_remote_conn_queue(srp, sqp) == B_FALSE) {
+ sqp->sq_status = SVP_S_FATAL;
+ sqp->sq_func(sqp, arg);
+ }
+ mutex_exit(&srp->sr_lock);
+}
+
+/*
+ * This is a request to do a VL3 look-up that originated internally as opposed
+ * to coming from varpd. As such we need a slightly different query callback
+ * function upon completion and don't go through the normal path with the svp_t.
+ */
+void
+svp_remote_vl3_logreq(svp_remote_t *srp, svp_query_t *sqp, uint32_t vid,
+ const struct sockaddr *addr, svp_query_f func, void *arg)
+{
+ svp_remote_vl3_common(srp, sqp, addr, func, arg, vid);
+}
+
+void
+svp_remote_vl3_lookup(svp_t *svp, svp_query_t *sqp,
+ const struct sockaddr *addr, void *arg)
+{
+ svp_remote_t *srp = svp->svp_remote;
+
+ sqp->sq_svp = svp;
+ svp_remote_vl3_common(srp, sqp, addr, svp_remote_vl3_lookup_cb,
+ arg, svp->svp_vid);
+}
+
+static void
+svp_remote_log_request_cb(svp_query_t *sqp, void *arg)
+{
+ svp_remote_t *srp = sqp->sq_arg;
+
+ assert(sqp->sq_wdata != NULL);
+ if (sqp->sq_status == SVP_S_OK)
+ svp_shootdown_logr_cb(srp, sqp->sq_status, sqp->sq_wdata,
+ sqp->sq_size);
+ else
+ svp_shootdown_logr_cb(srp, sqp->sq_status, NULL, 0);
+}
+
+void
+svp_remote_log_request(svp_remote_t *srp, svp_query_t *sqp, void *buf,
+ size_t buflen)
+{
+ svp_log_req_t *logr = &sqp->sq_rdun.sdq_logr;
+ boolean_t queued;
+
+ sqp->sq_func = svp_remote_log_request_cb;
+ sqp->sq_state = SVP_QUERY_INIT;
+ sqp->sq_arg = srp;
+ sqp->sq_header.svp_ver = htons(SVP_CURRENT_VERSION);
+ sqp->sq_header.svp_op = htons(SVP_R_LOG_REQ);
+ sqp->sq_header.svp_size = htonl(sizeof (svp_log_req_t));
+ sqp->sq_header.svp_id = id_alloc(svp_idspace);
+ if (sqp->sq_header.svp_id == (id_t)-1)
+ libvarpd_panic("failed to allcoate from svp_idspace: %d",
+ errno);
+ sqp->sq_header.svp_crc32 = htonl(0);
+ sqp->sq_rdata = logr;
+ sqp->sq_rsize = sizeof (svp_log_req_t);
+ sqp->sq_wdata = buf;
+ sqp->sq_wsize = buflen;
+
+ logr->svlr_count = htonl(buflen);
+ bcopy(&srp->sr_uip, logr->svlr_ip, sizeof (struct in6_addr));
+
+ /*
+ * If this fails, there isn't much that we can't do. Give the callback
+ * with a fatal status.
+ */
+ mutex_enter(&srp->sr_lock);
+ queued = svp_remote_conn_queue(srp, sqp);
+ mutex_exit(&srp->sr_lock);
+
+ if (queued == B_FALSE)
+ svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
+}
+
+static void
+svp_remote_lrm_request_cb(svp_query_t *sqp, void *arg)
+{
+ svp_remote_t *srp = arg;
+
+ svp_shootdown_lrm_cb(srp, sqp->sq_status);
+}
+
+void
+svp_remote_lrm_request(svp_remote_t *srp, svp_query_t *sqp, void *buf,
+ size_t buflen)
+{
+ boolean_t queued;
+ svp_lrm_req_t *svrr = buf;
+
+ sqp->sq_func = svp_remote_lrm_request_cb;
+ sqp->sq_state = SVP_QUERY_INIT;
+ sqp->sq_arg = srp;
+ sqp->sq_header.svp_ver = htons(SVP_CURRENT_VERSION);
+ sqp->sq_header.svp_op = htons(SVP_R_LOG_RM);
+ sqp->sq_header.svp_size = htonl(buflen);
+ sqp->sq_header.svp_id = id_alloc(svp_idspace);
+ if (sqp->sq_header.svp_id == (id_t)-1)
+ libvarpd_panic("failed to allcoate from svp_idspace: %d",
+ errno);
+ sqp->sq_header.svp_crc32 = htonl(0);
+ sqp->sq_rdata = buf;
+ sqp->sq_rsize = buflen;
+ sqp->sq_wdata = NULL;
+ sqp->sq_wsize = 0;
+
+ /*
+ * We need to fix up the count to be in proper network order.
+ */
+ svrr->svrr_count = htonl(svrr->svrr_count);
+
+ /*
+ * If this fails, there isn't much that we can't do. Give the callback
+ * with a fatal status.
+ */
+ mutex_enter(&srp->sr_lock);
+ queued = svp_remote_conn_queue(srp, sqp);
+ mutex_exit(&srp->sr_lock);
+
+ if (queued == B_FALSE)
+ svp_shootdown_logr_cb(srp, SVP_S_FATAL, NULL, 0);
+}
+
+/* ARGSUSED */
+void
+svp_remote_dns_timer(void *unused)
+{
+ svp_remote_t *s;
+ mutex_enter(&svp_remote_lock);
+ for (s = avl_first(&svp_remote_tree); s != NULL;
+ s = AVL_NEXT(&svp_remote_tree, s)) {
+ svp_host_queue(s);
+ }
+ mutex_exit(&svp_remote_lock);
+}
+
+void
+svp_remote_resolved(svp_remote_t *srp, struct addrinfo *newaddrs)
+{
+ struct addrinfo *a;
+ svp_conn_t *scp;
+ int ngen;
+
+ mutex_enter(&srp->sr_lock);
+ srp->sr_gen++;
+ ngen = srp->sr_gen;
+ mutex_exit(&srp->sr_lock);
+
+ for (a = newaddrs; a != NULL; a = a->ai_next) {
+ struct in6_addr in6;
+ struct in6_addr *addrp;
+
+ if (a->ai_family != AF_INET && a->ai_family != AF_INET6)
+ continue;
+
+ if (a->ai_family == AF_INET) {
+ struct sockaddr_in *v4;
+ v4 = (struct sockaddr_in *)a->ai_addr;
+ addrp = &in6;
+ IN6_INADDR_TO_V4MAPPED(&v4->sin_addr, addrp);
+ } else {
+ struct sockaddr_in6 *v6;
+ v6 = (struct sockaddr_in6 *)a->ai_addr;
+ addrp = &v6->sin6_addr;
+ }
+
+ mutex_enter(&srp->sr_lock);
+ for (scp = list_head(&srp->sr_conns); scp != NULL;
+ scp = list_next(&srp->sr_conns, scp)) {
+ mutex_enter(&scp->sc_lock);
+ if (bcmp(addrp, &scp->sc_addr,
+ sizeof (struct in6_addr)) == 0) {
+ scp->sc_gen = ngen;
+ mutex_exit(&scp->sc_lock);
+ break;
+ }
+ mutex_exit(&scp->sc_lock);
+ }
+
+ /*
+ * We need to be careful in the assumptions that we make here,
+ * as there's a good chance that svp_conn_create will
+ * drop the svp_remote_t`sr_lock to kick off its effective event
+ * loop.
+ */
+ if (scp == NULL)
+ (void) svp_conn_create(srp, addrp);
+ mutex_exit(&srp->sr_lock);
+ }
+
+ /*
+ * Now it's time to clean things up. We do not actively clean up the
+ * current connections that we have, instead allowing them to stay
+ * around assuming that they're still useful. Instead, we go through and
+ * purge the degraded list for anything that's from an older generation.
+ */
+ mutex_enter(&srp->sr_lock);
+ for (scp = list_head(&srp->sr_conns); scp != NULL;
+ scp = list_next(&srp->sr_conns, scp)) {
+ boolean_t fall = B_FALSE;
+ mutex_enter(&scp->sc_lock);
+ if (scp->sc_gen < srp->sr_gen)
+ fall = B_TRUE;
+ mutex_exit(&scp->sc_lock);
+ if (fall == B_TRUE)
+ svp_conn_fallout(scp);
+ }
+ mutex_exit(&srp->sr_lock);
+}
+
+/*
+ * This connection is in the process of being reset, we need to reassign all of
+ * its queries to other places or mark them as fatal. Note that the first
+ * connection was the one in flight when this failed. We always mark it as
+ * failed to avoid trying to reset its state.
+ */
+void
+svp_remote_reassign(svp_remote_t *srp, svp_conn_t *scp)
+{
+ boolean_t first = B_TRUE;
+ assert(MUTEX_HELD(&srp->sr_lock));
+ assert(MUTEX_HELD(&srp->sr_lock));
+ svp_query_t *sqp;
+
+ /*
+ * As we try to reassigning all of its queries, remove it from the list.
+ */
+ list_remove(&srp->sr_conns, scp);
+
+ while ((sqp = list_remove_head(&scp->sc_queries)) != NULL) {
+
+ if (first == B_TRUE) {
+ sqp->sq_status = SVP_S_FATAL;
+ sqp->sq_func(sqp, sqp->sq_arg);
+ continue;
+ }
+
+ sqp->sq_acttime = -1;
+
+ /*
+ * We may want to maintain a queue of these for some time rather
+ * than just failing them all.
+ */
+ if (svp_remote_conn_queue(srp, sqp) == B_FALSE) {
+ sqp->sq_status = SVP_S_FATAL;
+ sqp->sq_func(sqp, sqp->sq_arg);
+ }
+ }
+
+ /*
+ * Now that we're done, go ahead and re-insert.
+ */
+ list_insert_tail(&srp->sr_conns, scp);
+}
+
+void
+svp_remote_degrade(svp_remote_t *srp, svp_degrade_state_t flag)
+{
+ int sf, nf;
+ char buf[256];
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+
+ if (flag == SVP_RD_ALL || flag == 0)
+ libvarpd_panic("invalid flag passed to degrade");
+
+ if ((flag & srp->sr_degrade) != 0) {
+ return;
+ }
+
+ sf = ffs(srp->sr_degrade);
+ nf = ffs(flag);
+ srp->sr_degrade |= flag;
+ if (sf == 0 || sf > nf) {
+ svp_t *svp;
+ svp_remote_mkfmamsg(srp, flag, buf, sizeof (buf));
+
+ for (svp = avl_first(&srp->sr_tree); svp != NULL;
+ svp = AVL_NEXT(&srp->sr_tree, svp)) {
+ libvarpd_fma_degrade(svp->svp_hdl, buf);
+ }
+ }
+}
+
+void
+svp_remote_restore(svp_remote_t *srp, svp_degrade_state_t flag)
+{
+ int sf, nf;
+
+ assert(MUTEX_HELD(&srp->sr_lock));
+ sf = ffs(srp->sr_degrade);
+ if ((srp->sr_degrade & flag) != flag)
+ return;
+ srp->sr_degrade &= ~flag;
+ nf = ffs(srp->sr_degrade);
+
+ /*
+ * If we're now empty, restore the device. If we still are degraded, but
+ * we now have a higher base than we used to, change the message.
+ */
+ if (srp->sr_degrade == 0) {
+ svp_t *svp;
+ for (svp = avl_first(&srp->sr_tree); svp != NULL;
+ svp = AVL_NEXT(&srp->sr_tree, svp)) {
+ libvarpd_fma_restore(svp->svp_hdl);
+ }
+ } else if (nf != sf) {
+ svp_t *svp;
+ char buf[256];
+
+ svp_remote_mkfmamsg(srp, 1U << (nf - 1), buf, sizeof (buf));
+ for (svp = avl_first(&srp->sr_tree); svp != NULL;
+ svp = AVL_NEXT(&srp->sr_tree, svp)) {
+ libvarpd_fma_degrade(svp->svp_hdl, buf);
+ }
+ }
+}
+
+void
+svp_remote_shootdown_vl3_cb(svp_query_t *sqp, void *arg)
+{
+ svp_shoot_vl3_t *squery = arg;
+ svp_log_vl3_t *svl3 = squery->ssv_vl3;
+ svp_sdlog_t *sdl = squery->ssv_log;
+
+ if (sqp->sq_status == SVP_S_OK) {
+ svp_t *svp, lookup;
+
+ svp_remote_t *srp = sdl->sdl_remote;
+ svp_vl3_ack_t *vl3a = (svp_vl3_ack_t *)sqp->sq_wdata;
+
+ lookup.svp_vid = ntohl(svl3->svl3_vnetid);
+ mutex_enter(&srp->sr_lock);
+ if ((svp = avl_find(&srp->sr_tree, &lookup, NULL)) != NULL) {
+ svp->svp_cb.scb_vl3_inject(svp, ntohs(svl3->svl3_vlan),
+ (struct in6_addr *)svl3->svl3_ip, vl3a->sl3a_mac,
+ NULL);
+ }
+ mutex_exit(&srp->sr_lock);
+
+ }
+
+ svp_shootdown_vl3_cb(sqp->sq_status, svl3, sdl);
+
+ umem_free(squery, sizeof (svp_shoot_vl3_t));
+}
+
+void
+svp_remote_shootdown_vl3(svp_remote_t *srp, svp_log_vl3_t *svl3,
+ svp_sdlog_t *sdl)
+{
+ svp_shoot_vl3_t *squery;
+
+ squery = umem_zalloc(sizeof (svp_shoot_vl3_t), UMEM_DEFAULT);
+ if (squery == NULL) {
+ svp_shootdown_vl3_cb(SVP_S_FATAL, svl3, sdl);
+ return;
+ }
+
+ squery->ssv_vl3 = svl3;
+ squery->ssv_log = sdl;
+ squery->ssv_sock.sin6_family = AF_INET6;
+ bcopy(svl3->svl3_ip, &squery->ssv_sock.sin6_addr,
+ sizeof (svl3->svl3_ip));
+ svp_remote_vl3_logreq(srp, &squery->ssv_query, ntohl(svl3->svl3_vnetid),
+ (struct sockaddr *)&squery->ssv_sock, svp_remote_shootdown_vl3_cb,
+ squery);
+}
+
+void
+svp_remote_shootdown_vl2(svp_remote_t *srp, svp_log_vl2_t *svl2)
+{
+ svp_t *svp, lookup;
+
+ lookup.svp_vid = ntohl(svl2->svl2_vnetid);
+ mutex_enter(&srp->sr_lock);
+ if ((svp = avl_find(&srp->sr_tree, &lookup, NULL)) != NULL) {
+ svp->svp_cb.scb_vl2_invalidate(svp, svl2->svl2_mac);
+ }
+ mutex_exit(&srp->sr_lock);
+}
+
+int
+svp_remote_init(void)
+{
+ svp_idspace = id_space_create("svp_req_ids", 1, INT32_MAX);
+ if (svp_idspace == NULL)
+ return (errno);
+ avl_create(&svp_remote_tree, svp_remote_comparator,
+ sizeof (svp_remote_t), offsetof(svp_remote_t, sr_gnode));
+ svp_dns_timer.st_func = svp_remote_dns_timer;
+ svp_dns_timer.st_arg = NULL;
+ svp_dns_timer.st_oneshot = B_FALSE;
+ svp_dns_timer.st_value = svp_dns_timer_rate;
+ svp_timer_add(&svp_dns_timer);
+ return (0);
+}
+
+void
+svp_remote_fini(void)
+{
+ svp_timer_remove(&svp_dns_timer);
+ avl_destroy(&svp_remote_tree);
+ if (svp_idspace == NULL)
+ id_space_destroy(svp_idspace);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c
new file mode 100644
index 0000000000..76afb2519f
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_shootdown.c
@@ -0,0 +1,474 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Shootdown processing logic.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+#include <umem.h>
+#include <sys/uuid.h>
+#include <assert.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/debug.h>
+
+#include <libvarpd_provider.h>
+#include <libvarpd_svp.h>
+
+/*
+ * When we've determined that there's nothing left for us to do, then we go
+ * ahead and wait svp_shootdown_base seconds + up to an additional
+ * svp_shootdown_base seconds before asking again. However, if there is actually
+ * some work going on, just use the svp_shootdown_cont time.
+ */
+static int svp_shootdown_base = 5;
+static int svp_shootdown_cont = 1;
+
+/*
+ * These are sizes for our logack and logrm buffers. The sizing of the shootdown
+ * buffere would give us approximately 18 or so VL3 entries and 32 VL2 entries
+ * or some combination thereof. While it's a bit of overkill, we just use the
+ * same sized buffer for the list of uuids that we pass to remove log entries
+ * that we've acted upon.
+ */
+static int svp_shootdown_buf = 1024;
+
+static void
+svp_shootdown_schedule(svp_sdlog_t *sdl, boolean_t cont)
+{
+ assert(MUTEX_HELD(&sdl->sdl_lock));
+
+ if (cont == B_TRUE) {
+ sdl->sdl_timer.st_value = svp_shootdown_cont;
+ } else {
+ sdl->sdl_timer.st_value = svp_shootdown_base +
+ arc4random_uniform(svp_shootdown_base + 1);
+ }
+ svp_timer_add(&sdl->sdl_timer);
+}
+
+void
+svp_shootdown_lrm_cb(svp_remote_t *srp, svp_status_t status)
+{
+ svp_sdlog_t *sdl = &srp->sr_shoot;
+
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_flags &= ~SVP_SD_RUNNING;
+ svp_shootdown_schedule(sdl, B_TRUE);
+ mutex_exit(&sdl->sdl_lock);
+
+ if (status != SVP_S_OK) {
+ (void) bunyan_warn(svp_bunyan, "SVP_R_LOG_RM failed",
+ BUNYAN_T_STRING, "remote_host", srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port", srp->sr_rport,
+ BUNYAN_T_INT32, "status", status,
+ BUNYAN_T_END);
+ }
+}
+
+static void
+svp_shootdown_ref(svp_sdlog_t *sdl)
+{
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_ref++;
+ mutex_exit(&sdl->sdl_lock);
+}
+
+static void
+svp_shootdown_rele(svp_sdlog_t *sdl)
+{
+ svp_lrm_req_t *svrr = sdl->sdl_logrm;
+ boolean_t next;
+
+ mutex_enter(&sdl->sdl_lock);
+ VERIFY(sdl->sdl_ref > 0);
+ sdl->sdl_ref--;
+ if (sdl->sdl_ref > 0) {
+ mutex_exit(&sdl->sdl_lock);
+ return;
+ }
+
+ /*
+ * At this point we know that we hold the last reference, therefore it's
+ * safe for us to go ahead and clean up and move on and attempt to
+ * deliver the reply. We always deliver the reply by going through the
+ * timer. This can be rather important as the final reference may be
+ * coming through a failed query and it's not always safe for us to
+ * callback into the remote routines from this context.
+ *
+ * We should only do this if we have a non-zero number of entries to
+ * take down.
+ */
+ sdl->sdl_flags &= ~SVP_SD_RUNNING;
+ if (svrr->svrr_count > 0) {
+ sdl->sdl_flags |= SVP_SD_DORM;
+ next = B_TRUE;
+ } else {
+ next = B_FALSE;
+ }
+ svp_shootdown_schedule(sdl, next);
+ mutex_exit(&sdl->sdl_lock);
+}
+
+/*
+ * This is a callback used to indicate that the VL3 lookup has completed and an
+ * entry, if any, has been injected. If the command succeeded, eg. we got that
+ * the status was OK or that it was not found, then we will add it to he list to
+ * shoot down. Otherwise, there's nothing else for us to really do here.
+ */
+void
+svp_shootdown_vl3_cb(svp_status_t status, svp_log_vl3_t *vl3, svp_sdlog_t *sdl)
+{
+ svp_lrm_req_t *svrr = sdl->sdl_logrm;
+
+ mutex_enter(&sdl->sdl_lock);
+ if (status == SVP_S_OK || status == SVP_S_NOTFOUND) {
+ bcopy(vl3->svl3_id, &svrr->svrr_ids[svrr->svrr_count * 16],
+ UUID_LEN);
+ svrr->svrr_count++;
+ }
+ mutex_exit(&sdl->sdl_lock);
+
+ svp_shootdown_rele(sdl);
+}
+
+static int
+svp_shootdown_logr_shoot(void *data, svp_log_type_t type, void *arg)
+{
+ svp_sdlog_t *sdl = arg;
+ svp_remote_t *srp = sdl->sdl_remote;
+ svp_lrm_req_t *svrr = sdl->sdl_logrm;
+
+ if (type != SVP_LOG_VL2 && type != SVP_LOG_VL3)
+ libvarpd_panic("encountered unknown type: %d\n", type);
+
+ if (type == SVP_LOG_VL2) {
+ svp_log_vl2_t *svl2 = data;
+ svp_remote_shootdown_vl2(srp, svl2);
+ mutex_enter(&sdl->sdl_lock);
+ bcopy(svl2->svl2_id, &svrr->svrr_ids[svrr->svrr_count * 16],
+ UUID_LEN);
+ svrr->svrr_count++;
+ mutex_exit(&sdl->sdl_lock);
+ } else {
+ svp_log_vl3_t *svl3 = data;
+
+ /* Take a hold for the duration of this request */
+ svp_shootdown_ref(sdl);
+ svp_remote_shootdown_vl3(srp, svl3, sdl);
+ }
+
+ return (0);
+}
+
+static int
+svp_shootdown_logr_count(void *data, svp_log_type_t type, void *arg)
+{
+ uint_t *u = arg;
+ *u = *u + 1;
+ return (0);
+}
+
+
+static int
+svp_shootdown_logr_iter(svp_remote_t *srp, void *buf, size_t len,
+ int (*cb)(void *, svp_log_type_t, void *), void *arg)
+{
+ int ret;
+ off_t cboff = 0;
+ uint32_t *typep, type;
+ svp_log_vl2_t *svl2;
+ svp_log_vl3_t *svl3;
+
+ /* Adjust for initial status word */
+ assert(len >= sizeof (uint32_t));
+ len -= sizeof (uint32_t);
+ cboff += sizeof (uint32_t);
+
+ while (len > 0) {
+ size_t opsz;
+
+ if (len < sizeof (uint32_t)) {
+ (void) bunyan_warn(svp_bunyan,
+ "failed to get initial shootdown tag",
+ BUNYAN_T_STRING, "remote_host", srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port", srp->sr_rport,
+ BUNYAN_T_INT32, "response_size", cboff + len,
+ BUNYAN_T_INT32, "response_offset", cboff,
+ BUNYAN_T_END);
+ return (-1);
+ }
+
+ typep = buf + cboff;
+ type = ntohl(*typep);
+ if (type == SVP_LOG_VL2) {
+ opsz = sizeof (svp_log_vl2_t);
+ if (len < opsz) {
+ (void) bunyan_warn(svp_bunyan,
+ "not enough data for svp_log_vl2_t",
+ BUNYAN_T_STRING, "remote_host",
+ srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port",
+ srp->sr_rport,
+ BUNYAN_T_INT32, "response_size",
+ cboff + len,
+ BUNYAN_T_INT32, "response_offset", cboff,
+ BUNYAN_T_END);
+ return (-1);
+ }
+ svl2 = (void *)typep;
+ if ((ret = cb(svl2, type, arg)) != 0)
+ return (ret);
+ } else if (type == SVP_LOG_VL3) {
+
+ opsz = sizeof (svp_log_vl3_t);
+ if (len < opsz) {
+ (void) bunyan_warn(svp_bunyan,
+ "not enough data for svp_log_vl3_t",
+ BUNYAN_T_STRING, "remote_host",
+ srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port",
+ srp->sr_rport,
+ BUNYAN_T_INT32, "response_size",
+ cboff + len,
+ BUNYAN_T_INT32, "response_offset", cboff,
+ BUNYAN_T_END);
+ return (-1);
+ }
+ svl3 = (void *)typep;
+ if ((ret = cb(svl3, type, arg)) != 0)
+ return (ret);
+ } else {
+ (void) bunyan_warn(svp_bunyan,
+ "unknown log structure type",
+ BUNYAN_T_STRING, "remote_host",
+ srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port", srp->sr_rport,
+ BUNYAN_T_INT32, "response_size", cboff + len,
+ BUNYAN_T_INT32, "response_offset", cboff,
+ BUNYAN_T_INT32, "structure_type", type,
+ BUNYAN_T_END);
+ return (-1);
+ }
+ len -= opsz;
+ cboff += opsz;
+ }
+
+ return (0);
+}
+
+void
+svp_shootdown_logr_cb(svp_remote_t *srp, svp_status_t status, void *cbdata,
+ size_t cbsize)
+{
+ uint_t count;
+ svp_sdlog_t *sdl = &srp->sr_shoot;
+
+ if (status != SVP_S_OK) {
+ (void) bunyan_warn(svp_bunyan,
+ "log request not OK",
+ BUNYAN_T_STRING, "remote_host", srp->sr_hostname,
+ BUNYAN_T_INT32, "remote_port", srp->sr_rport,
+ BUNYAN_T_INT32, "response_size", cbsize,
+ BUNYAN_T_INT32, "status", status,
+ BUNYAN_T_END);
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_flags &= ~SVP_SD_RUNNING;
+ svp_shootdown_schedule(sdl, B_FALSE);
+ mutex_exit(&sdl->sdl_lock);
+ return;
+ }
+
+ /*
+ * First go ahead and count the number of entries. This effectively
+ * allows us to validate that all the data is valid, if this fails, then
+ * we fail the request.
+ */
+ count = 0;
+ if ((svp_shootdown_logr_iter(srp, cbdata, cbsize,
+ svp_shootdown_logr_count, &count)) != 0) {
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_flags &= ~SVP_SD_RUNNING;
+ svp_shootdown_schedule(sdl, B_FALSE);
+ mutex_exit(&sdl->sdl_lock);
+ return;
+ }
+
+ /*
+ * If we have no entries, then we're also done.
+ */
+ if (count == 0) {
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_flags &= ~SVP_SD_RUNNING;
+ svp_shootdown_schedule(sdl, B_FALSE);
+ mutex_exit(&sdl->sdl_lock);
+ return;
+ }
+
+ /*
+ * We have work to do. Because we may have asynchronous VL3 tasks, we're
+ * going to first grab a reference before we do the iteration. Then, for
+ * each asynchronous VL3 request we make, that'll also grab a hold. Once
+ * we're done with the iteration, we'll drop our hold. If that's the
+ * last one, it'll move on accordingly.
+ */
+ svp_shootdown_ref(sdl);
+ bzero(sdl->sdl_logrm, svp_shootdown_buf);
+
+ /*
+ * If this fails, we're going to determine what to do next based on the
+ * number of entries that were entered into the log removal. At this
+ * point success or failure don't really look different, all it changes
+ * is how many entries we have to remove.
+ */
+ (void) svp_shootdown_logr_iter(srp, cbdata, cbsize,
+ svp_shootdown_logr_shoot, sdl);
+
+ /*
+ * Now that we're done with our work, release the hold. If we don't have
+ * any vl3 tasks outstanding, this'll trigger the next phase of the log
+ * removals.
+ */
+ svp_shootdown_rele(sdl);
+}
+
+static void
+svp_shootdown_timer(void *arg)
+{
+ svp_sdlog_t *sdl = arg;
+ svp_remote_t *srp = sdl->sdl_remote;
+ boolean_t init = B_TRUE;
+
+ mutex_enter(&sdl->sdl_lock);
+
+ /*
+ * If we've been asked to quiesce, we're done.
+ */
+ if ((sdl->sdl_flags & SVP_SD_QUIESCE) != 0) {
+ mutex_exit(&sdl->sdl_lock);
+ return;
+ }
+
+ /*
+ * We shouldn't be able to have ourselves currently be running and reach
+ * here. If that's the case, we should immediately panic.
+ */
+ if ((sdl->sdl_flags & SVP_SD_RUNNING) != 0) {
+ libvarpd_panic("remote %p shootdown timer fired while still "
+ "running", srp);
+ }
+
+ if ((sdl->sdl_flags & SVP_SD_DORM) != 0) {
+ sdl->sdl_flags &= ~SVP_SD_DORM;
+ init = B_FALSE;
+ }
+
+ sdl->sdl_flags |= SVP_SD_RUNNING;
+ mutex_exit(&sdl->sdl_lock);
+
+ if (init == B_FALSE) {
+ svp_lrm_req_t *svrr = sdl->sdl_logrm;
+
+ bzero(&sdl->sdl_query, sizeof (svp_query_t));
+ svp_remote_lrm_request(sdl->sdl_remote, &sdl->sdl_query, svrr,
+ sizeof (*svrr) + 16 * svrr->svrr_count);
+ } else {
+ bzero(&sdl->sdl_query, sizeof (svp_query_t));
+ svp_remote_log_request(srp, &sdl->sdl_query, sdl->sdl_logack,
+ svp_shootdown_buf);
+ }
+}
+
+void
+svp_shootdown_fini(svp_remote_t *srp)
+{
+ svp_sdlog_t *sdl = &srp->sr_shoot;
+
+ mutex_enter(&sdl->sdl_lock);
+ sdl->sdl_flags |= SVP_SD_QUIESCE;
+ mutex_exit(&sdl->sdl_lock);
+
+ svp_timer_remove(&sdl->sdl_timer);
+
+ mutex_enter(&sdl->sdl_lock);
+
+ /*
+ * Normally svp_timer_remove would be enough. However, the query could
+ * have been put out again outside of the svp_timer interface. Therefore
+ * we still need to check for SVP_SD_RUNNING.
+ */
+ while (sdl->sdl_flags & SVP_SD_RUNNING)
+ (void) cond_wait(&sdl->sdl_cond, &sdl->sdl_lock);
+ mutex_exit(&sdl->sdl_lock);
+
+ umem_free(sdl->sdl_logack, svp_shootdown_buf);
+ umem_free(sdl->sdl_logrm, svp_shootdown_buf);
+ sdl->sdl_logack = NULL;
+ sdl->sdl_logrm = NULL;
+ (void) cond_destroy(&sdl->sdl_cond);
+ (void) mutex_destroy(&sdl->sdl_lock);
+}
+
+void
+svp_shootdown_start(svp_remote_t *srp)
+{
+ svp_sdlog_t *sdl = &srp->sr_shoot;
+
+ mutex_enter(&sdl->sdl_lock);
+ svp_shootdown_schedule(sdl, B_FALSE);
+ mutex_exit(&sdl->sdl_lock);
+}
+
+int
+svp_shootdown_init(svp_remote_t *srp)
+{
+ int ret;
+ svp_sdlog_t *sdl = &srp->sr_shoot;
+ if ((ret = mutex_init(&sdl->sdl_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0)
+ return (ret);
+
+ if ((ret = cond_init(&sdl->sdl_cond, USYNC_THREAD, NULL)) != 0) {
+ (void) mutex_destroy(&sdl->sdl_lock);
+ return (ret);
+ }
+
+ if ((sdl->sdl_logack = umem_alloc(svp_shootdown_buf, UMEM_DEFAULT)) ==
+ NULL) {
+ ret = errno;
+ (void) cond_destroy(&sdl->sdl_cond);
+ (void) mutex_destroy(&sdl->sdl_lock);
+ return (ret);
+ }
+
+ if ((sdl->sdl_logrm = umem_alloc(svp_shootdown_buf, UMEM_DEFAULT)) ==
+ NULL) {
+ ret = errno;
+ umem_free(sdl->sdl_logack, svp_shootdown_buf);
+ (void) cond_destroy(&sdl->sdl_cond);
+ (void) mutex_destroy(&sdl->sdl_lock);
+ return (ret);
+ }
+
+ sdl->sdl_remote = srp;
+ sdl->sdl_timer.st_oneshot = B_TRUE;
+ sdl->sdl_timer.st_func = svp_shootdown_timer;
+ sdl->sdl_timer.st_arg = sdl;
+
+ return (0);
+}
diff --git a/usr/src/lib/varpd/svp/common/libvarpd_svp_timer.c b/usr/src/lib/varpd/svp/common/libvarpd_svp_timer.c
new file mode 100644
index 0000000000..10b02748f3
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/libvarpd_svp_timer.c
@@ -0,0 +1,150 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+#include <stddef.h>
+#include <libvarpd_svp.h>
+
+/*
+ * svp timer backend
+ *
+ * This implements all of the logic of maintaining a timer for the svp backend.
+ * We have a timer that fires at a one second tick. We maintain all of our
+ * events in avl tree, sorted by the tick that they need to be processed at.
+ *
+ * For more information, see the big theory statement in
+ * lib/varpd/svp/common/libvarpd_svp.c.
+ */
+
+int svp_tickrate = 1;
+static svp_event_t svp_timer_event;
+static mutex_t svp_timer_lock = ERRORCHECKMUTEX;
+static cond_t svp_timer_cv = DEFAULTCV;
+static avl_tree_t svp_timer_tree;
+static uint64_t svp_timer_nticks;
+
+static int
+svp_timer_comparator(const void *l, const void *r)
+{
+ const svp_timer_t *lt, *rt;
+
+ lt = l;
+ rt = r;
+
+ if (lt->st_expire > rt->st_expire)
+ return (1);
+ else if (lt->st_expire < rt->st_expire)
+ return (-1);
+
+ /*
+ * Multiple timers can have the same delivery time, so sort within that
+ * by the address of the timer itself.
+ */
+ if ((uintptr_t)lt > (uintptr_t)rt)
+ return (1);
+ else if ((uintptr_t)lt < (uintptr_t)rt)
+ return (-1);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+svp_timer_tick(port_event_t *pe, void *arg)
+{
+ mutex_enter(&svp_timer_lock);
+ svp_timer_nticks++;
+
+ for (;;) {
+ svp_timer_t *t;
+
+ t = avl_first(&svp_timer_tree);
+ if (t == NULL || t->st_expire > svp_timer_nticks)
+ break;
+
+ avl_remove(&svp_timer_tree, t);
+
+ /*
+ * We drop this while performing an operation so that way state
+ * can advance in the face of a long-running callback.
+ */
+ t->st_delivering = B_TRUE;
+ mutex_exit(&svp_timer_lock);
+ t->st_func(t->st_arg);
+ mutex_enter(&svp_timer_lock);
+ t->st_delivering = B_FALSE;
+ (void) cond_broadcast(&svp_timer_cv);
+ if (t->st_oneshot == B_FALSE) {
+ t->st_expire += t->st_value;
+ avl_add(&svp_timer_tree, t);
+ }
+ }
+ mutex_exit(&svp_timer_lock);
+}
+
+void
+svp_timer_add(svp_timer_t *stp)
+{
+ if (stp->st_value == 0)
+ libvarpd_panic("tried to add svp timer with zero value");
+
+ mutex_enter(&svp_timer_lock);
+ stp->st_delivering = B_FALSE;
+ stp->st_expire = svp_timer_nticks + stp->st_value;
+ avl_add(&svp_timer_tree, stp);
+ mutex_exit(&svp_timer_lock);
+}
+
+void
+svp_timer_remove(svp_timer_t *stp)
+{
+ mutex_enter(&svp_timer_lock);
+
+ /*
+ * If the event in question is not currently being delivered, then we
+ * can stop it before it next fires. If it is currently being delivered,
+ * we need to wait for that to finish. Because we hold the timer lock,
+ * we know that it cannot be rearmed. Therefore, we make sure the one
+ * shot is set to zero, and wait until it's no longer set to delivering.
+ */
+ if (stp->st_delivering == B_FALSE) {
+ avl_remove(&svp_timer_tree, stp);
+ mutex_exit(&svp_timer_lock);
+ return;
+ }
+
+ stp->st_oneshot = B_TRUE;
+ while (stp->st_delivering == B_TRUE)
+ (void) cond_wait(&svp_timer_cv, &svp_timer_lock);
+
+ mutex_exit(&svp_timer_lock);
+}
+
+int
+svp_timer_init(void)
+{
+ int ret;
+
+ svp_timer_event.se_func = svp_timer_tick;
+ svp_timer_event.se_arg = NULL;
+
+ avl_create(&svp_timer_tree, svp_timer_comparator, sizeof (svp_timer_t),
+ offsetof(svp_timer_t, st_link));
+
+ if ((ret = svp_event_timer_init(&svp_timer_event)) != 0) {
+ avl_destroy(&svp_timer_tree);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/varpd/svp/common/llib-lvarpd_svp b/usr/src/lib/varpd/svp/common/llib-lvarpd_svp
new file mode 100644
index 0000000000..03c34f4fcb
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/llib-lvarpd_svp
@@ -0,0 +1,18 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
diff --git a/usr/src/lib/varpd/svp/common/mapfile-vers b/usr/src/lib/varpd/svp/common/mapfile-vers
new file mode 100644
index 0000000000..6b7c5a5067
--- /dev/null
+++ b/usr/src/lib/varpd/svp/common/mapfile-vers
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/svp/i386/Makefile b/usr/src/lib/varpd/svp/i386/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/svp/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/svp/sparc/Makefile b/usr/src/lib/varpd/svp/sparc/Makefile
new file mode 100644
index 0000000000..f2b4f63da5
--- /dev/null
+++ b/usr/src/lib/varpd/svp/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/varpd/svp/sparcv9/Makefile b/usr/src/lib/varpd/svp/sparcv9/Makefile
new file mode 100644
index 0000000000..d552642882
--- /dev/null
+++ b/usr/src/lib/varpd/svp/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/xml/os_dtd.c b/usr/src/lib/xml/os_dtd.c
new file mode 100644
index 0000000000..579e99ba3c
--- /dev/null
+++ b/usr/src/lib/xml/os_dtd.c
@@ -0,0 +1,238 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Utility functions for working with XML documents that are validated against
+ * Document Type Definitions (DTD) shipped in the operating system.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <zone.h>
+
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include "os_dtd.h"
+
+struct os_dtd_path {
+ os_dtd_id_t odp_id;
+ const char *odp_name;
+ const char *odp_public_ident;
+ const char *odp_path;
+};
+
+static os_dtd_path_t os_dtd_paths[] = {
+ /*
+ * DTDs for Zones infrastructure:
+ */
+ { OS_DTD_ZONES_BRAND, "brand",
+ "-//Sun Microsystems Inc//DTD Brands//EN",
+ "/usr/share/lib/xml/dtd/brand.dtd.1" },
+ { OS_DTD_ZONES_ZONE, "zone",
+ "-//Sun Microsystems Inc//DTD Zones//EN",
+ "/usr/share/lib/xml/dtd/zonecfg.dtd.1" },
+ { OS_DTD_ZONES_PLATFORM, "platform",
+ "-//Sun Microsystems Inc//Zones Platform//EN",
+ "/usr/share/lib/xml/dtd/zone_platform.dtd.1" },
+
+ /*
+ * DTDs for smf(5):
+ */
+ { OS_DTD_SMF_SERVICE_BUNDLE, "service_bundle",
+ NULL,
+ "/usr/share/lib/xml/dtd/service_bundle.dtd.1" },
+
+ { OS_DTD_UNKNOWN, NULL, NULL, NULL }
+};
+
+/*
+ * Check this document to see if it references the public identifier of a
+ * well-known DTD that we ship with the operating system. If there is no DTD,
+ * or the public identifier is unknown to us, return OS_DTD_UNKNOWN.
+ */
+os_dtd_id_t
+os_dtd_identify(xmlDocPtr doc)
+{
+ xmlDtdPtr dp;
+ int i;
+
+ if ((dp = xmlGetIntSubset(doc)) == NULL) {
+ /*
+ * This document does not have an internal subset pointing
+ * to a DTD.
+ */
+ errno = EIO;
+ return (OS_DTD_UNKNOWN);
+ }
+
+ /*
+ * The use of a symbolic name via the public identifier is preferred.
+ * Check to see if the document refers to a public identifier for any
+ * well-known DTD:
+ */
+ for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
+ os_dtd_path_t *odp = &os_dtd_paths[i];
+ const xmlChar *pubid = (const xmlChar *)odp->odp_public_ident;
+
+ if (dp->ExternalID == NULL || odp->odp_public_ident == NULL) {
+ continue;
+ }
+
+ if (xmlStrEqual(pubid, dp->ExternalID)) {
+ return (odp->odp_id);
+ }
+ }
+
+ /*
+ * If a public identifier is not present, or does not match any known
+ * DTD, fall back to inspecting the system identifier.
+ */
+ for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
+ os_dtd_path_t *odp = &os_dtd_paths[i];
+ char uri[sizeof ("file://") + MAXPATHLEN];
+ const xmlChar *path = (const xmlChar *)odp->odp_path;
+
+ if (dp->SystemID == NULL || odp->odp_path == NULL) {
+ continue;
+ }
+
+ /*
+ * The system identifier may be a regular path.
+ */
+ if (xmlStrEqual(path, dp->SystemID)) {
+ return (odp->odp_id);
+ }
+
+ /*
+ * The system identifier may also be a "file://"
+ * URI referring to a path:
+ */
+ (void) snprintf(uri, sizeof (uri), "file://%s", odp->odp_path);
+ if (xmlStrEqual((const xmlChar *)uri, dp->SystemID)) {
+ return (odp->odp_id);
+ }
+ }
+
+ errno = ENOENT;
+ return (OS_DTD_UNKNOWN);
+}
+
+static os_dtd_path_t *
+os_dtd_lookup(os_dtd_id_t id)
+{
+ int i;
+
+ for (i = 0; os_dtd_paths[i].odp_id != OS_DTD_UNKNOWN; i++) {
+ os_dtd_path_t *odp = &os_dtd_paths[i];
+
+ if (odp->odp_id == id) {
+ return (odp);
+ }
+ }
+
+ errno = ENOENT;
+ return (NULL);
+}
+
+/*
+ * If this document references a DTD, remove that reference (the "internal
+ * subset"). Install a new internal subset reference to the well-known
+ * operating system DTD passed by the caller. The URI in this reference will
+ * respect the current native system prefix (e.g. "/native") if there is one,
+ * such as when running in a branded zone.
+ */
+int
+os_dtd_attach(xmlDocPtr doc, os_dtd_id_t id)
+{
+ xmlDtdPtr dp;
+ os_dtd_path_t *odp;
+ const char *zroot = zone_get_nroot();
+ char uri[sizeof ("file://") + MAXPATHLEN];
+
+ if ((odp = os_dtd_lookup(id)) == NULL) {
+ return (-1);
+ }
+
+ if ((dp = xmlGetIntSubset(doc)) != NULL) {
+ /*
+ * This document already has an internal subset. Remove it
+ * before attaching the new one.
+ */
+ xmlUnlinkNode((xmlNodePtr)dp);
+ xmlFreeNode((xmlNodePtr)dp);
+ }
+
+ /*
+ * The "system identifier" of this internal subset must refer to the
+ * path in the filesystem where the DTD file (the external subset) is
+ * stored. If we are running in a branded zone, that file may be at a
+ * different path (e.g. under "/native").
+ */
+ (void) snprintf(uri, sizeof (uri), "file://%s%s", zroot != NULL ?
+ zroot : "", odp->odp_path);
+
+ if (xmlCreateIntSubset(doc, (const xmlChar *)odp->odp_name,
+ (const xmlChar *)odp->odp_public_ident,
+ (const xmlChar *)uri) == NULL) {
+ errno = EIO;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static void
+os_dtd_print_nothing(void *ctx, const char *msg, ...)
+{
+}
+
+int
+os_dtd_validate(xmlDocPtr doc, boolean_t emit_messages, boolean_t *valid)
+{
+ int ret;
+ xmlValidCtxtPtr cvp;
+ os_dtd_id_t dtdid;
+
+ if ((dtdid = os_dtd_identify(doc)) != OS_DTD_UNKNOWN) {
+ /*
+ * This document refers to a well-known DTD shipped with
+ * the operating system. Ensure that it points to the
+ * correct local path for validation in the current context.
+ */
+ if (os_dtd_attach(doc, dtdid) != 0) {
+ return (-1);
+ }
+ }
+
+ if ((cvp = xmlNewValidCtxt()) == NULL) {
+ return (-1);
+ }
+
+ if (!emit_messages) {
+ cvp->error = os_dtd_print_nothing;
+ cvp->warning = os_dtd_print_nothing;
+ }
+
+ ret = xmlValidateDocument(cvp, doc);
+ xmlFreeValidCtxt(cvp);
+
+ *valid = (ret == 1 ? B_TRUE : B_FALSE);
+ return (0);
+}
diff --git a/usr/src/lib/xml/os_dtd.h b/usr/src/lib/xml/os_dtd.h
new file mode 100644
index 0000000000..c6fe24a293
--- /dev/null
+++ b/usr/src/lib/xml/os_dtd.h
@@ -0,0 +1,49 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _OS_DTD_H
+#define _OS_DTD_H
+
+/*
+ * Utility functions for working with XML documents that are validated against
+ * Document Type Definitions (DTD) shipped in the operating system.
+ */
+
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum os_dtd_id {
+ OS_DTD_UNKNOWN = 0,
+ OS_DTD_ZONES_BRAND,
+ OS_DTD_ZONES_ZONE,
+ OS_DTD_ZONES_PLATFORM,
+ OS_DTD_SMF_SERVICE_BUNDLE
+} os_dtd_id_t;
+
+typedef struct os_dtd_path os_dtd_path_t;
+
+extern os_dtd_id_t os_dtd_identify(xmlDocPtr);
+extern int os_dtd_attach(xmlDocPtr, os_dtd_id_t);
+extern int os_dtd_validate(xmlDocPtr, boolean_t, boolean_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OS_DTD_H */