diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-03 12:41:42 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-03 12:41:42 +0300 |
commit | 7790c66bf2e26a4f34f2b42766d92e6c61f3930d (patch) | |
tree | abb337e47be4fbaac5a533dc936019223c9f01a3 | |
parent | ace54abd2ddae8facfce059d9442866517fc4b58 (diff) | |
download | mailutils-7790c66bf2e26a4f34f2b42766d92e6c61f3930d.tar.gz mailutils-7790c66bf2e26a4f34f2b42766d92e6c61f3930d.tar.bz2 |
fmtcheck: use symbolic label names by default
Actual program counters may differ between different architecture, so avoid
using them in the testsuite.
* mh/fmtcheck.c: New option -pc requires printing program counters. Unless
this option is used, -disass prints only labels where needed.
* mh/mh.h (mh_format_dump_disass): Change signature.
* mh/mh_format.c (mh_format_dump_disass): Take additional flag indicating
whether to print program counters. Compute and print program labels, unless
this flag is non-zero.
* mh/tests/fmtcomp.at: Don't expect program counters in disassembled code.
-rw-r--r-- | mh/fmtcheck.c | 12 | ||||
-rw-r--r-- | mh/mh.h | 2 | ||||
-rw-r--r-- | mh/mh_format.c | 167 | ||||
-rw-r--r-- | mh/tests/fmtcomp.at | 228 |
4 files changed, 286 insertions, 123 deletions
diff --git a/mh/fmtcheck.c b/mh/fmtcheck.c index 8c8509744..b0d7d37e2 100644 --- a/mh/fmtcheck.c +++ b/mh/fmtcheck.c | |||
@@ -31,6 +31,7 @@ static int debug_option; | |||
31 | static char *input_file; | 31 | static char *input_file; |
32 | static size_t width; | 32 | static size_t width; |
33 | static size_t msgno; | 33 | static size_t msgno; |
34 | static int pc_option; | ||
34 | 35 | ||
35 | void | 36 | void |
36 | opt_formfile (struct mu_parseopt *po, struct mu_option *opt, char const *arg) | 37 | opt_formfile (struct mu_parseopt *po, struct mu_option *opt, char const *arg) |
@@ -58,12 +59,15 @@ static struct mu_option options[] = { | |||
58 | { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT, | 59 | { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT, |
59 | N_("use this format string"), | 60 | N_("use this format string"), |
60 | mu_c_string, NULL, opt_format }, | 61 | mu_c_string, NULL, opt_format }, |
61 | { "dump", 0, NULL, MU_OPTION_HIDDEN, | 62 | { "dump", 0, NULL, MU_OPTION_DEFAULT, |
62 | N_("dump the listing of compiled format code"), | 63 | N_("dump the listing of compiled format code"), |
63 | mu_c_bool, &dump_option }, | 64 | mu_c_bool, &dump_option }, |
64 | { "disassemble", 0, NULL, MU_OPTION_HIDDEN, | 65 | { "disassemble", 0, NULL, MU_OPTION_DEFAULT, |
65 | N_("dump disassembled format code"), | 66 | N_("dump disassembled format code"), |
66 | mu_c_bool, &disass_option }, | 67 | mu_c_bool, &disass_option }, |
68 | { "pc", 0, NULL, MU_OPTION_DEFAULT, | ||
69 | N_("print program counter along with disassembled code (implies --disassemble)"), | ||
70 | mu_c_bool, &pc_option }, | ||
67 | { "debug", 0, NULL, MU_OPTION_DEFAULT, | 71 | { "debug", 0, NULL, MU_OPTION_DEFAULT, |
68 | N_("enable parser debugging output"), | 72 | N_("enable parser debugging output"), |
69 | mu_c_bool, &debug_option }, | 73 | mu_c_bool, &debug_option }, |
@@ -94,6 +98,8 @@ int | |||
94 | main (int argc, char **argv) | 98 | main (int argc, char **argv) |
95 | { | 99 | { |
96 | mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL); | 100 | mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL); |
101 | if (pc_option) | ||
102 | disass_option = 1; | ||
97 | switch (argc) | 103 | switch (argc) |
98 | { | 104 | { |
99 | case 0: | 105 | case 0: |
@@ -123,7 +129,7 @@ main (int argc, char **argv) | |||
123 | if (dump_option) | 129 | if (dump_option) |
124 | mh_format_dump_code (format); | 130 | mh_format_dump_code (format); |
125 | if (disass_option) | 131 | if (disass_option) |
126 | mh_format_dump_disass (format); | 132 | mh_format_dump_disass (format, pc_option); |
127 | 133 | ||
128 | if (input_file) | 134 | if (input_file) |
129 | run (); | 135 | run (); |
@@ -182,7 +182,7 @@ void mh_fvm_run (mh_fvm_t fvm, mu_message_t msg, size_t msgno); | |||
182 | int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret); | 182 | int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret); |
183 | 183 | ||
184 | void mh_format_dump_code (mh_format_t fmt); | 184 | void mh_format_dump_code (mh_format_t fmt); |
185 | void mh_format_dump_disass (mh_format_t fmt); | 185 | void mh_format_dump_disass (mh_format_t fmt, int addr); |
186 | 186 | ||
187 | #define MH_FMT_PARSE_DEFAULT 0 | 187 | #define MH_FMT_PARSE_DEFAULT 0 |
188 | #define MH_FMT_PARSE_TREE 0x01 | 188 | #define MH_FMT_PARSE_TREE 0x01 |
diff --git a/mh/mh_format.c b/mh/mh_format.c index 86eeb4ff3..0f1d4b728 100644 --- a/mh/mh_format.c +++ b/mh/mh_format.c | |||
@@ -1896,8 +1896,128 @@ _get_builtin_name (mh_builtin_fp ptr) | |||
1896 | return NULL; | 1896 | return NULL; |
1897 | } | 1897 | } |
1898 | 1898 | ||
1899 | /* Label array is used when disassembling the code, in order to create. | ||
1900 | meaningful label names. The array elements starting from index 1 keep | ||
1901 | the code addesses to which branch instructions point, in ascending order. | ||
1902 | Element 0 keeps the number of addresses stored. Thus, the label | ||
1903 | array LAB with contents { 3, 2, 5, 7 } declares three labels: "L1" on | ||
1904 | address 2, "L2", on address 5, and "L3" on address 7. | ||
1905 | */ | ||
1906 | |||
1907 | /* Find in LAB the index of the label corresponding to the given PC. Return | ||
1908 | 0 if no label found. */ | ||
1909 | size_t | ||
1910 | find_label (size_t *lab, size_t pc) | ||
1911 | { | ||
1912 | if (lab) | ||
1913 | { | ||
1914 | size_t i; | ||
1915 | for (i = 1; i <= lab[0]; i++) | ||
1916 | { | ||
1917 | if (lab[i] == pc) | ||
1918 | return i; | ||
1919 | } | ||
1920 | } | ||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1924 | static int | ||
1925 | comp_pc (const void *a, const void *b) | ||
1926 | { | ||
1927 | size_t pca = *(size_t*)a; | ||
1928 | size_t pcb = *(size_t*)b; | ||
1929 | if (pca < pcb) | ||
1930 | return -1; | ||
1931 | else if (pca > pcb) | ||
1932 | return 1; | ||
1933 | return 0; | ||
1934 | } | ||
1935 | |||
1936 | /* Extract a label array from a compiled format FMT. */ | ||
1937 | static size_t * | ||
1938 | extract_labels (mh_format_t fmt) | ||
1939 | { | ||
1940 | size_t *lab; | ||
1941 | size_t pc; | ||
1942 | long n; | ||
1943 | |||
1944 | lab = mu_calloc (fmt->progcnt, sizeof (lab[0])); | ||
1945 | lab[0] = 0; | ||
1946 | for (pc = 1; pc < fmt->progcnt; ) | ||
1947 | { | ||
1948 | mh_opcode_t opcode = MHI_OPCODE (fmt->prog[pc++]); | ||
1949 | if (opcode == mhop_stop) | ||
1950 | break; | ||
1951 | switch (opcode) | ||
1952 | { | ||
1953 | case mhop_branch: | ||
1954 | case mhop_brzn: | ||
1955 | case mhop_brzs: | ||
1956 | n = MHI_NUM (fmt->prog[pc++]); | ||
1957 | if (!find_label (lab, pc + n - 1)) | ||
1958 | lab[++lab[0]] = pc + n - 1; | ||
1959 | break; | ||
1960 | |||
1961 | case mhop_setn: | ||
1962 | pc += 2; | ||
1963 | break; | ||
1964 | |||
1965 | case mhop_sets: | ||
1966 | case mhop_ldcomp: | ||
1967 | pc += 2 + MHI_NUM (fmt->prog[pc + 1]); | ||
1968 | break; | ||
1969 | |||
1970 | case mhop_movn: | ||
1971 | case mhop_movs: | ||
1972 | pc += 2; | ||
1973 | break; | ||
1974 | |||
1975 | case mhop_ldbody: | ||
1976 | case mhop_call: | ||
1977 | case mhop_fmtspec: | ||
1978 | pc++; | ||
1979 | break; | ||
1980 | |||
1981 | case mhop_printlit: | ||
1982 | pc += 1 + MHI_NUM (fmt->prog[pc]); | ||
1983 | break; | ||
1984 | |||
1985 | case mhop_atoi: | ||
1986 | case mhop_itoa: | ||
1987 | case mhop_printn: | ||
1988 | case mhop_prints: | ||
1989 | break; | ||
1990 | |||
1991 | default: | ||
1992 | abort (); | ||
1993 | } | ||
1994 | } | ||
1995 | if (lab[0] > 0) | ||
1996 | qsort (lab + 1, lab[0], sizeof lab[0], comp_pc); | ||
1997 | return lab; | ||
1998 | } | ||
1999 | |||
2000 | /* Print to *PBUF (of size *PSZ) the label corresponding to the address PC. | ||
2001 | If there's no label having this address (in particular, if LAB==NULL), | ||
2002 | format the address itself to *PBUF. | ||
2003 | Reallocate *PBUF, updating *PSZ, if necessary. | ||
2004 | */ | ||
1899 | void | 2005 | void |
1900 | mh_format_dump_disass (mh_format_t fmt) | 2006 | format_label (size_t *lab, size_t pc, char **pbuf, size_t *psz) |
2007 | { | ||
2008 | size_t ln = find_label (lab, pc); | ||
2009 | if (ln) | ||
2010 | mu_asnprintf (pbuf, psz, "L%ld", (long) ln); | ||
2011 | else | ||
2012 | mu_asnprintf (pbuf, psz, "%ld", (long) pc); | ||
2013 | } | ||
2014 | |||
2015 | /* Dump disassembled code of FMT to stdout. If ADDR is 0, print label names | ||
2016 | where necessary, otherwise, prefix each line of output with its program | ||
2017 | counter in decimal. | ||
2018 | */ | ||
2019 | void | ||
2020 | mh_format_dump_disass (mh_format_t fmt, int addr) | ||
1901 | { | 2021 | { |
1902 | mh_instr_t *prog = fmt->prog; | 2022 | mh_instr_t *prog = fmt->prog; |
1903 | size_t pc = 1; | 2023 | size_t pc = 1; |
@@ -1908,14 +2028,46 @@ mh_format_dump_disass (mh_format_t fmt) | |||
1908 | [R_ACC] = "acc" | 2028 | [R_ACC] = "acc" |
1909 | }; | 2029 | }; |
1910 | static char c_trans[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; | 2030 | static char c_trans[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; |
2031 | size_t *lab; | ||
2032 | size_t lc; | ||
2033 | char *lbuf = NULL; | ||
2034 | size_t lsz = 0; | ||
1911 | 2035 | ||
1912 | if (!prog) | 2036 | if (!prog) |
1913 | return; | 2037 | return; |
2038 | |||
2039 | if (!addr) | ||
2040 | lab = extract_labels (fmt); | ||
2041 | else | ||
2042 | lab = NULL; | ||
2043 | lc = lab ? 1 : 0; | ||
2044 | |||
1914 | while (!stop) | 2045 | while (!stop) |
1915 | { | 2046 | { |
1916 | mh_opcode_t opcode; | 2047 | mh_opcode_t opcode; |
1917 | 2048 | ||
1918 | printf ("% 4.4ld: ", (long) pc); |