25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

285 lines
7.0 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. "flag"
  20. "fmt"
  21. "io"
  22. "os"
  23. "sort"
  24. "strconv"
  25. "strings"
  26. )
  27. var verbose = flag.Bool("verbose", false, "If true, prints a status message at the end.")
  28. // libraryNames must be kept in sync with the enum in err.h. The generated code
  29. // will contain static assertions to enforce this.
  30. var libraryNames = []string{
  31. "NONE",
  32. "SYS",
  33. "BN",
  34. "RSA",
  35. "DH",
  36. "EVP",
  37. "BUF",
  38. "OBJ",
  39. "PEM",
  40. "DSA",
  41. "X509",
  42. "ASN1",
  43. "CONF",
  44. "CRYPTO",
  45. "EC",
  46. "SSL",
  47. "BIO",
  48. "PKCS7",
  49. "PKCS8",
  50. "X509V3",
  51. "RAND",
  52. "ENGINE",
  53. "OCSP",
  54. "UI",
  55. "COMP",
  56. "ECDSA",
  57. "ECDH",
  58. "HMAC",
  59. "DIGEST",
  60. "CIPHER",
  61. "HKDF",
  62. "USER",
  63. }
  64. // stringList is a map from uint32 -> string which can output data for a sorted
  65. // list as C literals.
  66. type stringList struct {
  67. // entries is an array of keys and offsets into |stringData|. The
  68. // offsets are in the bottom 15 bits of each uint32 and the key is the
  69. // top 17 bits.
  70. entries []uint32
  71. // internedStrings contains the same strings as are in |stringData|,
  72. // but allows for easy deduplication. It maps a string to its offset in
  73. // |stringData|.
  74. internedStrings map[string]uint32
  75. stringData []byte
  76. }
  77. func newStringList() *stringList {
  78. return &stringList{
  79. internedStrings: make(map[string]uint32),
  80. }
  81. }
  82. // offsetMask is the bottom 15 bits. It's a mask that selects the offset from a
  83. // uint32 in entries.
  84. const offsetMask = 0x7fff
  85. func (st *stringList) Add(key uint32, value string) error {
  86. if key&offsetMask != 0 {
  87. return errors.New("need bottom 15 bits of the key for the offset")
  88. }
  89. offset, ok := st.internedStrings[value]
  90. if !ok {
  91. offset = uint32(len(st.stringData))
  92. if offset&offsetMask != offset {
  93. return errors.New("stringList overflow")
  94. }
  95. st.stringData = append(st.stringData, []byte(value)...)
  96. st.stringData = append(st.stringData, 0)
  97. st.internedStrings[value] = offset
  98. }
  99. for _, existing := range st.entries {
  100. if existing>>15 == key>>15 {
  101. panic("duplicate entry")
  102. }
  103. }
  104. st.entries = append(st.entries, key|offset)
  105. return nil
  106. }
  107. // keySlice is a type that implements sorting of entries values.
  108. type keySlice []uint32
  109. func (ks keySlice) Len() int {
  110. return len(ks)
  111. }
  112. func (ks keySlice) Less(i, j int) bool {
  113. return (ks[i] >> 15) < (ks[j] >> 15)
  114. }
  115. func (ks keySlice) Swap(i, j int) {
  116. ks[i], ks[j] = ks[j], ks[i]
  117. }
  118. func (st *stringList) buildList() []uint32 {
  119. sort.Sort(keySlice(st.entries))
  120. return st.entries
  121. }
  122. type stringWriter interface {
  123. io.Writer
  124. WriteString(string) (int, error)
  125. }
  126. func (st *stringList) WriteTo(out stringWriter, name string) {
  127. list := st.buildList()
  128. if *verbose {
  129. fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData))
  130. }
  131. values := "kOpenSSL" + name + "Values"
  132. out.WriteString("const uint32_t " + values + "[] = {\n")
  133. for _, v := range list {
  134. fmt.Fprintf(out, " 0x%x,\n", v)
  135. }
  136. out.WriteString("};\n\n")
  137. out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n")
  138. stringData := "kOpenSSL" + name + "StringData"
  139. out.WriteString("const char " + stringData + "[] =\n \"")
  140. for i, c := range st.stringData {
  141. if c == 0 {
  142. out.WriteString("\\0\"\n \"")
  143. continue
  144. }
  145. out.Write(st.stringData[i : i+1])
  146. }
  147. out.WriteString("\";\n\n")
  148. }
  149. type errorData struct {
  150. reasons *stringList
  151. libraryMap map[string]uint32
  152. }
  153. func (e *errorData) readErrorDataFile(filename string) error {
  154. inFile, err := os.Open(filename)
  155. if err != nil {
  156. return err
  157. }
  158. defer inFile.Close()
  159. scanner := bufio.NewScanner(inFile)
  160. comma := []byte(",")
  161. lineNo := 0
  162. for scanner.Scan() {
  163. lineNo++
  164. line := scanner.Bytes()
  165. if len(line) == 0 {
  166. continue
  167. }
  168. parts := bytes.Split(line, comma)
  169. if len(parts) != 3 {
  170. return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts))
  171. }
  172. libNum, ok := e.libraryMap[string(parts[0])]
  173. if !ok {
  174. return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename)
  175. }
  176. if libNum >= 64 {
  177. return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
  178. }
  179. key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */)
  180. if err != nil {
  181. return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
  182. }
  183. if key >= 2048 {
  184. return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
  185. }
  186. value := string(parts[2])
  187. listKey := libNum<<26 | uint32(key)<<15
  188. err = e.reasons.Add(listKey, value)
  189. if err != nil {
  190. return err
  191. }
  192. }
  193. return scanner.Err()
  194. }
  195. func main() {
  196. flag.Parse()
  197. e := &errorData{
  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/err.h>
  238. #include <openssl/type_check.h>
  239. `)
  240. for i, name := range libraryNames {
  241. fmt.Fprintf(out, "OPENSSL_STATIC_ASSERT(ERR_LIB_%s == %d, \"library value changed\");\n", name, i+1)
  242. }
  243. fmt.Fprintf(out, "OPENSSL_STATIC_ASSERT(ERR_NUM_LIBS == %d, \"number of libraries changed\");\n", len(libraryNames)+1)
  244. out.WriteString("\n")
  245. e.reasons.WriteTo(out, "Reason")
  246. }