You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

284 line
6.9 KiB

  1. /* Copyright (c) 2015, Google Inc.
  2. *
  3. * Permission to use, copy, modify, and/or distribute this software for any
  4. * purpose with or without fee is hereby granted, provided that the above
  5. * copyright notice and this permission notice appear in all copies.
  6. *
  7. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. package main
  15. import (
  16. "bufio"
  17. "bytes"
  18. "errors"
  19. "fmt"
  20. "io"
  21. "os"
  22. "sort"
  23. "strconv"
  24. "strings"
  25. )
  26. // libraryNames must be kept in sync with the enum in err.h. The generated code
  27. // will contain static assertions to enforce this.
  28. var libraryNames = []string{
  29. "NONE",
  30. "SYS",
  31. "BN",
  32. "RSA",
  33. "DH",
  34. "EVP",
  35. "BUF",
  36. "OBJ",
  37. "PEM",
  38. "DSA",
  39. "X509",
  40. "ASN1",
  41. "CONF",
  42. "CRYPTO",
  43. "EC",
  44. "SSL",
  45. "BIO",
  46. "PKCS7",
  47. "PKCS8",
  48. "X509V3",
  49. "RAND",
  50. "ENGINE",
  51. "OCSP",
  52. "UI",
  53. "COMP",
  54. "ECDSA",
  55. "ECDH",
  56. "HMAC",
  57. "DIGEST",
  58. "CIPHER",
  59. "USER",
  60. "HKDF",
  61. }
  62. // stringList is a map from uint32 -> string which can output data for a sorted
  63. // list as C literals.
  64. type stringList struct {
  65. // entries is an array of keys and offsets into |stringData|. The
  66. // offsets are in the bottom 15 bits of each uint32 and the key is the
  67. // top 17 bits.
  68. entries []uint32
  69. // internedStrings contains the same strings as are in |stringData|,
  70. // but allows for easy deduplication. It maps a string to its offset in
  71. // |stringData|.
  72. internedStrings map[string]uint32
  73. stringData []byte
  74. }
  75. func newStringList() *stringList {
  76. return &stringList{
  77. internedStrings: make(map[string]uint32),
  78. }
  79. }
  80. // offsetMask is the bottom 15 bits. It's a mask that selects the offset from a
  81. // uint32 in entries.
  82. const offsetMask = 0x7fff
  83. func (st *stringList) Add(key uint32, value string) error {
  84. if key&offsetMask != 0 {
  85. return errors.New("need bottom 15 bits of the key for the offset")
  86. }
  87. offset, ok := st.internedStrings[value]
  88. if !ok {
  89. offset = uint32(len(st.stringData))
  90. if offset&offsetMask != offset {
  91. return errors.New("stringList overflow")
  92. }
  93. st.stringData = append(st.stringData, []byte(value)...)
  94. st.stringData = append(st.stringData, 0)
  95. st.internedStrings[value] = offset
  96. }
  97. for _, existing := range st.entries {
  98. if existing>>15 == key>>15 {
  99. panic("duplicate entry")
  100. }
  101. }
  102. st.entries = append(st.entries, key|offset)
  103. return nil
  104. }
  105. // keySlice is a type that implements sorting of entries values.
  106. type keySlice []uint32
  107. func (ks keySlice) Len() int {
  108. return len(ks)
  109. }
  110. func (ks keySlice) Less(i, j int) bool {
  111. return (ks[i] >> 15) < (ks[j] >> 15)
  112. }
  113. func (ks keySlice) Swap(i, j int) {
  114. ks[i], ks[j] = ks[j], ks[i]
  115. }
  116. func (st *stringList) buildList() []uint32 {
  117. sort.Sort(keySlice(st.entries))
  118. return st.entries
  119. }
  120. type stringWriter interface {
  121. io.Writer
  122. WriteString(string) (int, error)
  123. }
  124. func (st *stringList) WriteTo(out stringWriter, name string) {
  125. list := st.buildList()
  126. fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData))
  127. out.WriteString("static const uint32_t k" + name + "Values[] = {\n")
  128. for _, v := range list {
  129. fmt.Fprintf(out, " 0x%x,\n", v)
  130. }
  131. out.WriteString("};\n\n")
  132. out.WriteString("static const char k" + name + "StringData[] =\n \"")
  133. for i, c := range st.stringData {
  134. if c == 0 {
  135. out.WriteString("\\0\"\n \"")
  136. continue
  137. }
  138. out.Write(st.stringData[i : i+1])
  139. }
  140. out.WriteString("\";\n\n")
  141. }
  142. type errorData struct {
  143. functions, reasons *stringList
  144. libraryMap map[string]uint32
  145. }
  146. func (e *errorData) readErrorDataFile(filename string) error {
  147. inFile, err := os.Open(filename)
  148. if err != nil {
  149. return err
  150. }
  151. defer inFile.Close()
  152. scanner := bufio.NewScanner(inFile)
  153. comma := []byte(",")
  154. lineNo := 0
  155. for scanner.Scan() {
  156. lineNo++
  157. line := scanner.Bytes()
  158. if len(line) == 0 {
  159. continue
  160. }
  161. parts := bytes.Split(line, comma)
  162. if len(parts) != 4 {
  163. return fmt.Errorf("bad line %d in %s: found %d values but want 4", lineNo, filename, len(parts))
  164. }
  165. libNum, ok := e.libraryMap[string(parts[0])]
  166. if !ok {
  167. return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename)
  168. }
  169. if libNum >= 64 {
  170. return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
  171. }
  172. key, err := strconv.ParseUint(string(parts[2]), 10 /* base */, 32 /* bit size */)
  173. if err != nil {
  174. return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
  175. }
  176. if key >= 2048 {
  177. return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
  178. }
  179. value := string(parts[3])
  180. listKey := libNum<<26 | uint32(key)<<15
  181. switch string(parts[1]) {
  182. case "function":
  183. err = e.functions.Add(listKey, value)
  184. case "reason":
  185. err = e.reasons.Add(listKey, value)
  186. default:
  187. return fmt.Errorf("bad line %d in %s: bad value type", lineNo, filename)
  188. }
  189. if err != nil {
  190. return err
  191. }
  192. }
  193. return scanner.Err()
  194. }
  195. func main() {
  196. e := &errorData{
  197. functions: newStringList(),
  198. reasons: newStringList(),
  199. libraryMap: make(map[string]uint32),
  200. }
  201. for i, name := range libraryNames {
  202. e.libraryMap[name] = uint32(i) + 1
  203. }
  204. cwd, err := os.Open(".")
  205. if err != nil {
  206. panic(err)
  207. }
  208. names, err := cwd.Readdirnames(-1)
  209. if err != nil {
  210. panic(err)
  211. }
  212. sort.Strings(names)
  213. for _, name := range names {
  214. if !strings.HasSuffix(name, ".errordata") {
  215. continue
  216. }
  217. if err := e.readErrorDataFile(name); err != nil {
  218. panic(err)
  219. }
  220. }
  221. out := os.Stdout
  222. out.WriteString(`/* Copyright (c) 2015, Google Inc.
  223. *
  224. * Permission to use, copy, modify, and/or distribute this software for any
  225. * purpose with or without fee is hereby granted, provided that the above
  226. * copyright notice and this permission notice appear in all copies.
  227. *
  228. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  229. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  230. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  231. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  232. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  233. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  234. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  235. /* This file was generated by err_data_generate.go. */
  236. #include <openssl/base.h>
  237. #include <openssl/type_check.h>
  238. `)
  239. for i, name := range libraryNames {
  240. fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_LIB_%s == %d, library_values_changed_%d);\n", name, i+1, i+1)
  241. }
  242. fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames) + 1)
  243. out.WriteString("\n")
  244. e.functions.WriteTo(out, "Function")
  245. e.reasons.WriteTo(out, "Reason")
  246. }