summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorAdam Langley <agl@google.com>2015-01-22 14:27:53 -0800
committerAdam Langley <agl@google.com>2015-01-30 16:52:14 -0800
commitd9e397b599b13d642138480a28c14db7a136bf05 (patch)
tree34bab61dc4ce323b123ad4614dbc07e86ea2f9ef /src/util
downloadexternal_boringssl-d9e397b599b13d642138480a28c14db7a136bf05.zip
external_boringssl-d9e397b599b13d642138480a28c14db7a136bf05.tar.gz
external_boringssl-d9e397b599b13d642138480a28c14db7a136bf05.tar.bz2
Initial commit of BoringSSL for Android.
Diffstat (limited to 'src/util')
-rw-r--r--src/util/32-bit-toolchain.cmake7
-rw-r--r--src/util/aarch64-toolchain.cmake6
-rw-r--r--src/util/all_tests.sh85
-rw-r--r--src/util/arm-toolchain.cmake6
-rw-r--r--src/util/clang-toolchain.cmake2
-rw-r--r--src/util/doc.config49
-rw-r--r--src/util/doc.css67
-rw-r--r--src/util/doc.go623
-rw-r--r--src/util/make_errors.go462
9 files changed, 1307 insertions, 0 deletions
diff --git a/src/util/32-bit-toolchain.cmake b/src/util/32-bit-toolchain.cmake
new file mode 100644
index 0000000..f3a10b7
--- /dev/null
+++ b/src/util/32-bit-toolchain.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_SYSTEM_PROCESSOR "x86")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -msse2" CACHE STRING "c++ flags")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -msse2" CACHE STRING "c flags")
+set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32 -msse2" CACHE STRING "asm flags")
diff --git a/src/util/aarch64-toolchain.cmake b/src/util/aarch64-toolchain.cmake
new file mode 100644
index 0000000..77f33ab
--- /dev/null
+++ b/src/util/aarch64-toolchain.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_SYSTEM_PROCESSOR "aarch64")
+set(CMAKE_CXX_COMPILER "/opt/gcc-linaro-4.9-2014.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++")
+set(CMAKE_C_COMPILER "/opt/gcc-linaro-4.9-2014.11-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc")
+set(CMAKE_EXE_LINKER_FLAGS "-static")
diff --git a/src/util/all_tests.sh b/src/util/all_tests.sh
new file mode 100644
index 0000000..bcb5c24
--- /dev/null
+++ b/src/util/all_tests.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+# Copyright (c) 2014, Google Inc.
+#
+# 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. */
+
+SRC=..
+if [ "$#" -ge 1 ]; then
+ SRC=$1
+fi
+
+TESTS="
+./crypto/base64/base64_test
+./crypto/bio/bio_test
+./crypto/bn/bn_test
+./crypto/bytestring/bytestring_test
+./crypto/cipher/aead_test aes-128-gcm $SRC/crypto/cipher/test/aes_128_gcm_tests.txt
+./crypto/cipher/aead_test aes-128-key-wrap $SRC/crypto/cipher/test/aes_128_key_wrap_tests.txt
+./crypto/cipher/aead_test aes-256-gcm $SRC/crypto/cipher/test/aes_256_gcm_tests.txt
+./crypto/cipher/aead_test aes-256-key-wrap $SRC/crypto/cipher/test/aes_256_key_wrap_tests.txt
+./crypto/cipher/aead_test chacha20-poly1305 $SRC/crypto/cipher/test/chacha20_poly1305_tests.txt
+./crypto/cipher/aead_test rc4-md5-tls $SRC/crypto/cipher/test/rc4_md5_tls_tests.txt
+./crypto/cipher/aead_test rc4-sha1-tls $SRC/crypto/cipher/test/rc4_sha1_tls_tests.txt
+./crypto/cipher/aead_test aes-128-cbc-sha1-tls $SRC/crypto/cipher/test/aes_128_cbc_sha1_tls_tests.txt
+./crypto/cipher/aead_test aes-128-cbc-sha1-tls-implicit-iv $SRC/crypto/cipher/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt
+./crypto/cipher/aead_test aes-128-cbc-sha256-tls $SRC/crypto/cipher/test/aes_128_cbc_sha256_tls_tests.txt
+./crypto/cipher/aead_test aes-256-cbc-sha1-tls $SRC/crypto/cipher/test/aes_256_cbc_sha1_tls_tests.txt
+./crypto/cipher/aead_test aes-256-cbc-sha1-tls-implicit-iv $SRC/crypto/cipher/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt
+./crypto/cipher/aead_test aes-256-cbc-sha256-tls $SRC/crypto/cipher/test/aes_256_cbc_sha256_tls_tests.txt
+./crypto/cipher/aead_test aes-256-cbc-sha384-tls $SRC/crypto/cipher/test/aes_256_cbc_sha384_tls_tests.txt
+./crypto/cipher/aead_test des-ede3-cbc-sha1-tls $SRC/crypto/cipher/test/des_ede3_cbc_sha1_tls_tests.txt
+./crypto/cipher/aead_test des-ede3-cbc-sha1-tls-implicit-iv $SRC/crypto/cipher/test/des_ede3_cbc_sha1_tls_implicit_iv_tests.txt
+./crypto/cipher/aead_test rc4-md5-ssl3 $SRC/crypto/cipher/test/rc4_md5_ssl3_tests.txt
+./crypto/cipher/aead_test rc4-sha1-ssl3 $SRC/crypto/cipher/test/rc4_sha1_ssl3_tests.txt
+./crypto/cipher/aead_test aes-128-cbc-sha1-ssl3 $SRC/crypto/cipher/test/aes_128_cbc_sha1_ssl3_tests.txt
+./crypto/cipher/aead_test aes-256-cbc-sha1-ssl3 $SRC/crypto/cipher/test/aes_256_cbc_sha1_ssl3_tests.txt
+./crypto/cipher/aead_test des-ede3-cbc-sha1-ssl3 $SRC/crypto/cipher/test/des_ede3_cbc_sha1_ssl3_tests.txt
+./crypto/cipher/cipher_test $SRC/crypto/cipher/test/cipher_test.txt
+./crypto/constant_time_test
+./crypto/dh/dh_test
+./crypto/digest/digest_test
+./crypto/dsa/dsa_test
+./crypto/ec/ec_test
+./crypto/ec/example_mul
+./crypto/ecdsa/ecdsa_test
+./crypto/err/err_test
+./crypto/evp/evp_test
+./crypto/evp/pbkdf_test
+./crypto/hkdf/hkdf_test
+./crypto/hmac/hmac_test
+./crypto/lhash/lhash_test
+./crypto/modes/gcm_test
+./crypto/pkcs8/pkcs12_test
+./crypto/rsa/rsa_test
+./crypto/x509/pkcs7_test
+./crypto/x509v3/tab_test
+./crypto/x509v3/v3name_test
+./ssl/pqueue/pqueue_test
+./ssl/ssl_test
+"
+
+IFS=$'\n'
+for bin in $TESTS; do
+ echo $bin
+ out=$(bash -c "$bin" | tail -n 1)
+ if [ $? -ne 0 ]; then
+ echo $bin failed to complete.
+ exit 1
+ fi
+
+ if [ "x$out" != "xPASS" ]; then
+ echo $bin failed to print PASS on the last line.
+ exit 1
+ fi
+done
diff --git a/src/util/arm-toolchain.cmake b/src/util/arm-toolchain.cmake
new file mode 100644
index 0000000..2dfd2bd
--- /dev/null
+++ b/src/util/arm-toolchain.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+set(CMAKE_SYSTEM_PROCESSOR "arm")
+set(CMAKE_CXX_COMPILER "/opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++")
+set(CMAKE_C_COMPILER "/opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc")
+set(CMAKE_EXE_LINKER_FLAGS "-static")
diff --git a/src/util/clang-toolchain.cmake b/src/util/clang-toolchain.cmake
new file mode 100644
index 0000000..8d81379
--- /dev/null
+++ b/src/util/clang-toolchain.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_CXX_COMPILER "/agl/chromium/src/third_party/llvm-build/Release+Asserts/bin/clang++")
+set(CMAKE_C_COMPILER "/agl/chromium/src/third_party/llvm-build/Release+Asserts/bin/clang")
diff --git a/src/util/doc.config b/src/util/doc.config
new file mode 100644
index 0000000..62db0f3
--- /dev/null
+++ b/src/util/doc.config
@@ -0,0 +1,49 @@
+{
+ "BaseDirectory": "..",
+ "Sections": [{
+ "Name": "Low-level infrastructure",
+ "Headers": [
+ "include/openssl/base64.h",
+ "include/openssl/bio.h",
+ "include/openssl/buf.h",
+ "include/openssl/bytestring.h",
+ "include/openssl/err.h",
+ "include/openssl/cpu.h",
+ "include/openssl/ex_data.h",
+ "include/openssl/lhash.h",
+ "include/openssl/mem.h",
+ "include/openssl/obj.h",
+ "include/openssl/stack.h",
+ "include/openssl/thread.h",
+ "include/openssl/time_support.h"
+ ]
+ },{
+ "Name": "Low-level crypto primitives",
+ "Headers": [
+ "include/openssl/aes.h",
+ "include/openssl/bn.h",
+ "include/openssl/des.h",
+ "include/openssl/dh.h",
+ "include/openssl/dsa.h",
+ "include/openssl/ec.h",
+ "include/openssl/ec_key.h",
+ "include/openssl/ecdh.h",
+ "include/openssl/ecdsa.h",
+ "include/openssl/engine.h",
+ "include/openssl/hmac.h",
+ "include/openssl/md5.h",
+ "include/openssl/modes.h",
+ "include/openssl/rc4.h",
+ "include/openssl/rsa.h",
+ "include/openssl/sha.h"
+ ]
+ },{
+ "Name": "Crypto interfaces",
+ "Headers": [
+ "include/openssl/digest.h",
+ "include/openssl/cipher.h",
+ "include/openssl/aead.h",
+ "include/openssl/evp.h"
+ ]
+ }]
+}
diff --git a/src/util/doc.css b/src/util/doc.css
new file mode 100644
index 0000000..ab653e4
--- /dev/null
+++ b/src/util/doc.css
@@ -0,0 +1,67 @@
+#main {
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 55em;
+ text-align: justify;
+}
+
+h2 {
+ font-family: monospace;
+ margin-bottom: 2em;
+ background-color: #b2c9db;
+ padding: 7px;
+ border-radius: 7px;
+}
+
+ol {
+ list-style: none;
+ margin-bottom: 4em;
+}
+
+li a {
+ color: black;
+}
+
+li.header {
+ margin-top: 1em;
+ margin-bottom: 0.3em;
+ font-weight: bold;
+}
+
+div.decl p:first-child {
+ margin-top: 2.5em;
+}
+
+div.decl p:first-child .first-word {
+ font-weight: bold;
+ font-family: monospace;
+}
+
+.sectionpreamble {
+ margin-top: 5em;
+}
+
+.sectionpreamble p:first-child {
+ font-weight: bold;
+ font-size: 1.5em;
+}
+
+.section pre {
+ background-color: #b2c9db;
+ padding: 5px;
+ border-radius: 5px;
+}
+
+td {
+ padding: 2px;
+}
+
+tr:nth-child(even) {
+ background-color: #eee;
+}
+
+tr.header td {
+ font-weight: bold;
+ padding-top: 1em;
+ padding-bottom: 0.5em;
+}
diff --git a/src/util/doc.go b/src/util/doc.go
new file mode 100644
index 0000000..7c96af8
--- /dev/null
+++ b/src/util/doc.go
@@ -0,0 +1,623 @@
+// doc generates HTML files from the comments in header files.
+//
+// doc expects to be given the path to a JSON file via the --config option.
+// From that JSON (which is defined by the Config struct) it reads a list of
+// header file locations and generates HTML files for each in the current
+// directory.
+
+package main
+
+import (
+ "bufio"
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "html/template"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// Config describes the structure of the config JSON file.
+type Config struct {
+ // BaseDirectory is a path to which other paths in the file are
+ // relative.
+ BaseDirectory string
+ Sections []ConfigSection
+}
+
+type ConfigSection struct {
+ Name string
+ // Headers is a list of paths to header files.
+ Headers []string
+}
+
+// HeaderFile is the internal representation of a header file.
+type HeaderFile struct {
+ // Name is the basename of the header file (e.g. "ex_data.html").
+ Name string
+ // Preamble contains a comment for the file as a whole. Each string
+ // is a separate paragraph.
+ Preamble []string
+ Sections []HeaderSection
+}
+
+type HeaderSection struct {
+ // Preamble contains a comment for a group of functions.
+ Preamble []string
+ Decls []HeaderDecl
+ // Num is just the index of the section. It's included in order to help
+ // text/template generate anchors.
+ Num int
+ // IsPrivate is true if the section contains private functions (as
+ // indicated by its name).
+ IsPrivate bool
+}
+
+type HeaderDecl struct {
+ // Comment contains a comment for a specific function. Each string is a
+ // paragraph. Some paragraph may contain \n runes to indicate that they
+ // are preformatted.
+ Comment []string
+ // Name contains the name of the function, if it could be extracted.
+ Name string
+ // Decl contains the preformatted C declaration itself.
+ Decl string
+ // Num is an index for the declaration, but the value is unique for all
+ // declarations in a HeaderFile. It's included in order to help
+ // text/template generate anchors.
+ Num int
+}
+
+const (
+ cppGuard = "#if defined(__cplusplus)"
+ commentStart = "/* "
+ commentEnd = " */"
+)
+
+func extractComment(lines []string, lineNo int) (comment []string, rest []string, restLineNo int, err error) {
+ if len(lines) == 0 {
+ return nil, lines, lineNo, nil
+ }
+
+ restLineNo = lineNo
+ rest = lines
+
+ if !strings.HasPrefix(rest[0], commentStart) {
+ panic("extractComment called on non-comment")
+ }
+ commentParagraph := rest[0][len(commentStart):]
+ rest = rest[1:]
+ restLineNo++
+
+ for len(rest) > 0 {
+ i := strings.Index(commentParagraph, commentEnd)
+ if i >= 0 {
+ if i != len(commentParagraph)-len(commentEnd) {
+ err = fmt.Errorf("garbage after comment end on line %d", restLineNo)
+ return
+ }
+ commentParagraph = commentParagraph[:i]
+ if len(commentParagraph) > 0 {
+ comment = append(comment, commentParagraph)
+ }
+ return
+ }
+
+ line := rest[0]
+ if !strings.HasPrefix(line, " *") {
+ err = fmt.Errorf("comment doesn't start with block prefix on line %d: %s", restLineNo, line)
+ return
+ }
+ line = line[2:]
+ if strings.HasPrefix(line, " ") {
+ /* Identing the lines of a paragraph marks them as
+ * preformatted. */
+ if len(commentParagraph) > 0 {
+ commentParagraph += "\n"
+ }
+ line = line[3:]
+ }
+ if len(line) > 0 {
+ commentParagraph = commentParagraph + line
+ if len(commentParagraph) > 0 && commentParagraph[0] == ' ' {
+ commentParagraph = commentParagraph[1:]
+ }
+ } else {
+ comment = append(comment, commentParagraph)
+ commentParagraph = ""
+ }
+ rest = rest[1:]
+ restLineNo++
+ }
+
+ err = errors.New("hit EOF in comment")
+ return
+}
+
+func extractDecl(lines []string, lineNo int) (decl string, rest []string, restLineNo int, err error) {
+ if len(lines) == 0 {
+ return "", lines, lineNo, nil
+ }
+
+ rest = lines
+ restLineNo = lineNo
+
+ var stack []rune
+ for len(rest) > 0 {
+ line := rest[0]
+ for _, c := range line {
+ switch c {
+ case '(', '{', '[':
+ stack = append(stack, c)
+ case ')', '}', ']':
+ if len(stack) == 0 {
+ err = fmt.Errorf("unexpected %c on line %d", c, restLineNo)
+ return
+ }
+ var expected rune
+ switch c {
+ case ')':
+ expected = '('
+ case '}':
+ expected = '{'
+ case ']':
+ expected = '['
+ default:
+ panic("internal error")
+ }
+ if last := stack[len(stack)-1]; last != expected {
+ err = fmt.Errorf("found %c when expecting %c on line %d", c, last, restLineNo)
+ return
+ }
+ stack = stack[:len(stack)-1]
+ }
+ }
+ if len(decl) > 0 {
+ decl += "\n"
+ }
+ decl += line
+ rest = rest[1:]
+ restLineNo++
+
+ if len(stack) == 0 && (len(decl) == 0 || decl[len(decl)-1] != '\\') {
+ break
+ }
+ }
+
+ return
+}
+
+func skipPast(s, skip string) string {
+ i := strings.Index(s, skip)
+ if i > 0 {
+ return s[len(skip):]
+ }
+ return s
+}
+
+func getNameFromDecl(decl string) (string, bool) {
+ if strings.HasPrefix(decl, "struct ") {
+ return "", false
+ }
+ decl = skipPast(decl, "STACK_OF(")
+ decl = skipPast(decl, "LHASH_OF(")
+ i := strings.Index(decl, "(")
+ if i < 0 {
+ return "", false
+ }
+ j := strings.LastIndex(decl[:i], " ")
+ if j < 0 {
+ return "", false
+ }
+ for j+1 < len(decl) && decl[j+1] == '*' {
+ j++
+ }
+ return decl[j+1 : i], true
+}
+
+func (config *Config) parseHeader(path string) (*HeaderFile, error) {
+ headerPath := filepath.Join(config.BaseDirectory, path)
+
+ headerFile, err := os.Open(headerPath)
+ if err != nil {
+ return nil, err
+ }
+ defer headerFile.Close()
+
+ scanner := bufio.NewScanner(headerFile)
+ var lines, oldLines []string
+ for scanner.Scan() {
+ lines = append(lines, scanner.Text())
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ lineNo := 0
+ found := false
+ for i, line := range lines {
+ lineNo++
+ if line == cppGuard {
+ lines = lines[i+1:]
+ lineNo++
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ return nil, errors.New("no C++ guard found")
+ }
+
+ if len(lines) == 0 || lines[0] != "extern \"C\" {" {
+ return nil, errors.New("no extern \"C\" found after C++ guard")
+ }
+ lineNo += 2
+ lines = lines[2:]
+
+ header := &HeaderFile{
+ Name: filepath.Base(path),
+ }
+
+ for i, line := range lines {
+ lineNo++
+ if len(line) > 0 {
+ lines = lines[i:]
+ break
+ }
+ }
+
+ oldLines = lines
+ if len(lines) > 0 && strings.HasPrefix(lines[0], commentStart) {
+ comment, rest, restLineNo, err := extractComment(lines, lineNo)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(rest) > 0 && len(rest[0]) == 0 {
+ if len(rest) < 2 || len(rest[1]) != 0 {
+ return nil, errors.New("preamble comment should be followed by two blank lines")
+ }
+ header.Preamble = comment
+ lineNo = restLineNo + 2
+ lines = rest[2:]
+ } else {
+ lines = oldLines
+ }
+ }
+
+ var sectionNumber, declNumber int
+
+ for {
+ // Start of a section.
+ if len(lines) == 0 {
+ return nil, errors.New("unexpected end of file")
+ }
+ line := lines[0]
+ if line == cppGuard {
+ break
+ }
+
+ if len(line) == 0 {
+ return nil, fmt.Errorf("blank line at start of section on line %d", lineNo)
+ }
+
+ section := HeaderSection{
+ Num: sectionNumber,
+ }
+ sectionNumber++
+
+ if strings.HasPrefix(line, commentStart) {
+ comment, rest, restLineNo, err := extractComment(lines, lineNo)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 && len(rest[0]) == 0 {
+ section.Preamble = comment
+ section.IsPrivate = len(comment) > 0 && strings.HasPrefix(comment[0], "Private functions")
+ lines = rest[1:]
+ lineNo = restLineNo + 1
+ }
+ }
+
+ for len(lines) > 0 {
+ line := lines[0]
+ if len(line) == 0 {
+ lines = lines[1:]
+ lineNo++
+ break
+ }
+ if line == cppGuard {
+ return nil, errors.New("hit ending C++ guard while in section")
+ }
+
+ var comment []string
+ var decl string
+ if strings.HasPrefix(line, commentStart) {
+ comment, lines, lineNo, err = extractComment(lines, lineNo)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if len(lines) == 0 {
+ return nil, errors.New("expected decl at EOF")
+ }
+ decl, lines, lineNo, err = extractDecl(lines, lineNo)
+ if err != nil {
+ return nil, err
+ }
+ name, ok := getNameFromDecl(decl)
+ if !ok {
+ name = ""
+ }
+ if last := len(section.Decls) - 1; len(name) == 0 && len(comment) == 0 && last >= 0 {
+ section.Decls[last].Decl += "\n" + decl
+ } else {
+ section.Decls = append(section.Decls, HeaderDecl{
+ Comment: comment,
+ Name: name,
+ Decl: decl,
+ Num: declNumber,
+ })
+ declNumber++
+ }
+
+ if len(lines) > 0 && len(lines[0]) == 0 {
+ lines = lines[1:]
+ lineNo++
+ }
+ }
+
+ header.Sections = append(header.Sections, section)
+ }
+
+ return header, nil
+}
+
+func firstSentence(paragraphs []string) string {
+ if len(paragraphs) == 0 {
+ return ""
+ }
+ s := paragraphs[0]
+ i := strings.Index(s, ". ")
+ if i >= 0 {
+ return s[:i]
+ }
+ if lastIndex := len(s) - 1; s[lastIndex] == '.' {
+ return s[:lastIndex]
+ }
+ return s
+}
+
+func markupPipeWords(s string) template.HTML {
+ ret := ""
+
+ for {
+ i := strings.Index(s, "|")
+ if i == -1 {
+ ret += s
+ break
+ }
+ ret += s[:i]
+ s = s[i+1:]
+
+ i = strings.Index(s, "|")
+ j := strings.Index(s, " ")
+ if i > 0 && (j == -1 || j > i) {
+ ret += "<tt>"
+ ret += s[:i]
+ ret += "</tt>"
+ s = s[i+1:]
+ } else {
+ ret += "|"
+ }
+ }
+
+ return template.HTML(ret)
+}
+
+func markupFirstWord(s template.HTML) template.HTML {
+ start := 0
+again:
+ end := strings.Index(string(s[start:]), " ")
+ if end > 0 {
+ end += start
+ w := strings.ToLower(string(s[start:end]))
+ if w == "a" || w == "an" || w == "deprecated:" {
+ start = end + 1
+ goto again
+ }
+ return s[:start] + "<span class=\"first-word\">" + s[start:end] + "</span>" + s[end:]
+ }
+ return s
+}
+
+func newlinesToBR(html template.HTML) template.HTML {
+ s := string(html)
+ if !strings.Contains(s, "\n") {
+ return html
+ }
+ s = strings.Replace(s, "\n", "<br>", -1)
+ s = strings.Replace(s, " ", "&nbsp;", -1)
+ return template.HTML(s)
+}
+
+func generate(outPath string, config *Config) (map[string]string, error) {
+ headerTmpl := template.New("headerTmpl")
+ headerTmpl.Funcs(template.FuncMap{
+ "firstSentence": firstSentence,
+ "markupPipeWords": markupPipeWords,
+ "markupFirstWord": markupFirstWord,
+ "newlinesToBR": newlinesToBR,
+ })
+ headerTmpl, err := headerTmpl.Parse(`<!DOCTYPE html>
+<html>
+ <head>
+ <title>BoringSSL - {{.Name}}</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="doc.css">
+ </head>
+
+ <body>
+ <div id="main">
+ <h2>{{.Name}}</h2>
+
+ {{range .Preamble}}<p>{{. | html | markupPipeWords}}</p>{{end}}
+
+ <ol>
+ {{range .Sections}}
+ {{if not .IsPrivate}}
+ {{if .Preamble}}<li class="header"><a href="#section-{{.Num}}">{{.Preamble | firstSentence | html | markupPipeWords}}</a></li>{{end}}
+ {{range .Decls}}
+ {{if .Name}}<li><a href="#decl-{{.Num}}"><tt>{{.Name}}</tt></a></li>{{end}}
+ {{end}}
+ {{end}}
+ {{end}}
+ </ol>
+
+ {{range .Sections}}
+ {{if not .IsPrivate}}
+ <div class="section">
+ {{if .Preamble}}
+ <div class="sectionpreamble">
+ <a name="section-{{.Num}}">
+ {{range .Preamble}}<p>{{. | html | markupPipeWords}}</p>{{end}}
+ </a>
+ </div>
+ {{end}}
+
+ {{range .Decls}}
+ <div class="decl">
+ <a name="decl-{{.Num}}">
+ {{range .Comment}}
+ <p>{{. | html | markupPipeWords | newlinesToBR | markupFirstWord}}</p>
+ {{end}}
+ <pre>{{.Decl}}</pre>
+ </a>
+ </div>
+ {{end}}
+ </div>
+ {{end}}
+ {{end}}
+ </div>
+ </body>
+</html>`)
+ if err != nil {
+ return nil, err
+ }
+
+ headerDescriptions := make(map[string]string)
+
+ for _, section := range config.Sections {
+ for _, headerPath := range section.Headers {
+ header, err := config.parseHeader(headerPath)
+ if err != nil {
+ return nil, errors.New("while parsing " + headerPath + ": " + err.Error())
+ }
+ headerDescriptions[header.Name] = firstSentence(header.Preamble)
+ filename := filepath.Join(outPath, header.Name+".html")
+ file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+ if err := headerTmpl.Execute(file, header); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return headerDescriptions, nil
+}
+
+func generateIndex(outPath string, config *Config, headerDescriptions map[string]string) error {
+ indexTmpl := template.New("indexTmpl")
+ indexTmpl.Funcs(template.FuncMap{
+ "baseName": filepath.Base,
+ "headerDescription": func(header string) string {
+ return headerDescriptions[header]
+ },
+ })
+ indexTmpl, err := indexTmpl.Parse(`<!DOCTYPE html5>
+
+ <head>
+ <title>BoringSSL - Headers</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" type="text/css" href="doc.css">
+ </head>
+
+ <body>
+ <div id="main">
+ <table>
+ {{range .Sections}}
+ <tr class="header"><td colspan="2">{{.Name}}</td></tr>
+ {{range .Headers}}
+ <tr><td><a href="{{. | baseName}}.html">{{. | baseName}}</a></td><td>{{. | baseName | headerDescription}}</td></tr>
+ {{end}}
+ {{end}}
+ </table>
+ </div>
+ </body>
+</html>`)
+
+ if err != nil {
+ return err
+ }
+
+ file, err := os.OpenFile(filepath.Join(outPath, "headers.html"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ if err := indexTmpl.Execute(file, config); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func main() {
+ var (
+ configFlag *string = flag.String("config", "", "Location of config file")
+ outputDir *string = flag.String("out", "", "Path to the directory where the output will be written")
+ config Config
+ )
+
+ flag.Parse()
+
+ if len(*configFlag) == 0 {
+ fmt.Printf("No config file given by --config\n")
+ os.Exit(1)
+ }
+
+ if len(*outputDir) == 0 {
+ fmt.Printf("No output directory given by --out\n")
+ os.Exit(1)
+ }
+
+ configBytes, err := ioutil.ReadFile(*configFlag)
+ if err != nil {
+ fmt.Printf("Failed to open config file: %s\n", err)
+ os.Exit(1)
+ }
+
+ if err := json.Unmarshal(configBytes, &config); err != nil {
+ fmt.Printf("Failed to parse config file: %s\n", err)
+ os.Exit(1)
+ }
+
+ headerDescriptions, err := generate(*outputDir, &config)
+ if err != nil {
+ fmt.Printf("Failed to generate output: %s\n", err)
+ os.Exit(1)
+ }
+
+ if err := generateIndex(*outputDir, &config, headerDescriptions); err != nil {
+ fmt.Printf("Failed to generate index: %s\n", err)
+ os.Exit(1)
+ }
+}
diff --git a/src/util/make_errors.go b/src/util/make_errors.go
new file mode 100644
index 0000000..5fd75e2
--- /dev/null
+++ b/src/util/make_errors.go
@@ -0,0 +1,462 @@
+// Copyright (c) 2014, Google Inc.
+//
+// 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. */
+
+package main
+
+import (
+ "bufio"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// ssl.h reserves values 1000 and above for error codes corresponding to
+// alerts. If automatically assigned reason codes exceed this value, this script
+// will error. This must be kept in sync with SSL_AD_REASON_OFFSET in ssl.h.
+const reservedReasonCode = 1000
+
+var resetFlag *bool = flag.Bool("reset", false, "If true, ignore current assignments and reassign from scratch")
+
+func makeErrors(reset bool) error {
+ dirName, err := os.Getwd()
+ if err != nil {
+ return err
+ }
+
+ lib := filepath.Base(dirName)
+ headerPath, err := findHeader(lib + ".h")
+ if err != nil {
+ return err
+ }
+ sourcePath := lib + "_error.c"
+
+ headerFile, err := os.Open(headerPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return fmt.Errorf("No header %s. Run in the right directory or touch the file.", headerPath)
+ }
+
+ return err
+ }
+
+ prefix := strings.ToUpper(lib)
+ functions, reasons, err := parseHeader(prefix, headerFile)
+ headerFile.Close()
+
+ if reset {
+ err = nil
+ functions = make(map[string]int)
+ // Retain any reason codes above reservedReasonCode.
+ newReasons := make(map[string]int)
+ for key, value := range reasons {
+ if value >= reservedReasonCode {
+ newReasons[key] = value
+ }
+ }
+ reasons = newReasons
+ }
+
+ if err != nil {
+ return err
+ }
+
+ dir, err := os.Open(".")
+ if err != nil {
+ return err
+ }
+ defer dir.Close()
+
+ filenames, err := dir.Readdirnames(-1)
+ if err != nil {
+ return err
+ }
+
+ for _, name := range filenames {
+ if !strings.HasSuffix(name, ".c") || name == sourcePath {
+ continue
+ }
+
+ if err := addFunctionsAndReasons(functions, reasons, name, prefix); err != nil {
+ return err
+ }
+ }
+
+ assignNewValues(functions, -1)
+ assignNewValues(reasons, reservedReasonCode)
+
+ headerFile, err = os.Open(headerPath)
+ if err != nil {
+ return err
+ }
+ defer headerFile.Close()
+
+ newHeaderFile, err := os.OpenFile(headerPath+".tmp", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
+ if err != nil {
+ return err
+ }
+ defer newHeaderFile.Close()
+
+ if err := writeHeaderFile(newHeaderFile, headerFile, prefix, functions, reasons); err != nil {
+ return err
+ }
+ os.Rename(headerPath+".tmp", headerPath)
+
+ sourceFile, err := os.OpenFile(sourcePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
+ if err != nil {
+ return err
+ }
+ defer sourceFile.Close()
+
+ fmt.Fprintf(sourceFile, `/* Copyright (c) 2014, Google Inc.
+ *
+ * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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 <openssl/err.h>
+
+#include <openssl/%s.h>
+
+const ERR_STRING_DATA %s_error_string_data[] = {
+`, lib, prefix)
+ outputStrings(sourceFile, lib, typeFunctions, functions)
+ outputStrings(sourceFile, lib, typeReasons, reasons)
+
+ sourceFile.WriteString(" {0, NULL},\n};\n")
+
+ return nil
+}
+
+func findHeader(basename string) (path string, err error) {
+ includeDir := filepath.Join("..", "include")
+
+ fi, err := os.Stat(includeDir)
+ if err != nil && os.IsNotExist(err) {
+ includeDir = filepath.Join("..", includeDir)
+ fi, err = os.Stat(includeDir)
+ }
+ if err != nil {
+ return "", errors.New("cannot find path to include directory")
+ }
+ if !fi.IsDir() {
+ return "", errors.New("include node is not a directory")
+ }
+ return filepath.Join(includeDir, "openssl", basename), nil
+}
+
+type assignment struct {
+ key string
+ value int
+}
+
+type assignmentsSlice []assignment
+
+func (a assignmentsSlice) Len() int {
+ return len(a)
+}
+
+func (a assignmentsSlice) Less(i, j int) bool {
+ return a[i].value < a[j].value
+}
+
+func (a assignmentsSlice) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func outputAssignments(w io.Writer, assignments map[string]int) {
+ var sorted assignmentsSlice
+
+ for key, value := range assignments {
+ sorted = append(sorted, assignment{key, value})
+ }
+
+ sort.Sort(sorted)
+
+ for _, assignment := range sorted {
+ fmt.Fprintf(w, "#define %s %d\n", assignment.key, assignment.value)
+ }
+}
+
+func parseDefineLine(line, lib string) (typ int, key string, value int, ok bool) {
+ if !strings.HasPrefix(line, "#define ") {
+ return
+ }
+
+ fields := strings.Fields(line)
+ if len(fields) != 3 {
+ return
+ }
+
+ funcPrefix := lib + "_F_"
+ reasonPrefix := lib + "_R_"
+
+ key = fields[1]
+ switch {
+ case strings.HasPrefix(key, funcPrefix):
+ typ = typeFunctions
+ case strings.HasPrefix(key, reasonPrefix):
+ typ = typeReasons
+ default:
+ return
+ }
+
+ var err error
+ if value, err = strconv.Atoi(fields[2]); err != nil {
+ return
+ }
+
+ ok = true
+ return
+}
+
+func writeHeaderFile(w io.Writer, headerFile io.Reader, lib string, functions, reasons map[string]int) error {
+ var last []byte
+ var haveLast, sawDefine bool
+ newLine := []byte("\n")
+
+ scanner := bufio.NewScanner(headerFile)
+ for scanner.Scan() {
+ line := scanner.Text()
+ _, _, _, ok := parseDefineLine(line, lib)
+ if ok {
+ sawDefine = true
+ continue
+ }
+
+ if haveLast {
+ w.Write(last)
+ w.Write(newLine)
+ }
+
+ if len(line) > 0 || !sawDefine {
+ last = []byte(line)
+ haveLast = true
+ } else {
+ haveLast = false
+ }
+ sawDefine = false
+ }
+
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+
+ outputAssignments(w, functions)
+ outputAssignments(w, reasons)
+ w.Write(newLine)
+
+ if haveLast {
+ w.Write(last)
+ w.Write(newLine)
+ }
+
+ return nil
+}
+
+const (
+ typeFunctions = iota
+ typeReasons
+)
+
+func outputStrings(w io.Writer, lib string, ty int, assignments map[string]int) {
+ lib = strings.ToUpper(lib)
+ prefixLen := len(lib + "_F_")
+
+ keys := make([]string, 0, len(assignments))
+ for key := range assignments {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+
+ for _, key := range keys {
+ var pack string
+ if ty == typeFunctions {
+ pack = key + ", 0"
+ } else {
+ pack = "0, " + key
+ }
+
+ fmt.Fprintf(w, " {ERR_PACK(ERR_LIB_%s, %s), \"%s\"},\n", lib, pack, key[prefixLen:])
+ }
+}
+
+func assignNewValues(assignments map[string]int, reserved int) {
+ max := 99
+
+ for _, value := range assignments {
+ if reserved >= 0 && value >= reserved {
+ continue
+ }
+ if value > max {
+ max = value
+ }
+ }
+
+ max++
+
+ for key, value := range assignments {
+ if value == -1 {
+ if reserved >= 0 && max >= reserved {
+ // If this happens, try passing
+ // -reset. Otherwise bump up reservedReasonCode.
+ panic("Automatically-assigned values exceeded limit!")
+ }
+ assignments[key] = max
+ max++
+ }
+ }
+}
+
+func handleDeclareMacro(line, join, macroName string, m map[string]int) {
+ if i := strings.Index(line, macroName); i >= 0 {
+ contents := line[i+len(macroName):]
+ if i := strings.Index(contents, ")"); i >= 0 {
+ contents = contents[:i]
+ args := strings.Split(contents, ",")
+ for i := range args {
+ args[i] = strings.TrimSpace(args[i])
+ }
+ if len(args) != 2 {
+ panic("Bad macro line: " + line)
+ }
+ token := args[0] + join + args[1]
+ if _, ok := m[token]; !ok {
+ m[token] = -1
+ }
+ }
+ }
+}
+
+func addFunctionsAndReasons(functions, reasons map[string]int, filename, prefix string) error {
+ file, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ prefix += "_"
+ reasonPrefix := prefix + "R_"
+ var currentFunction string
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Text()
+
+ if len(line) > 0 && unicode.IsLetter(rune(line[0])) {
+ /* Function start */
+ fields := strings.Fields(line)
+ for _, field := range fields {
+ if i := strings.Index(field, "("); i != -1 {
+ f := field[:i]
+ // The return type of some functions is
+ // a macro that contains a "(".
+ if f == "STACK_OF" {
+ continue
+ }
+ currentFunction = f
+ for len(currentFunction) > 0 && currentFunction[0] == '*' {
+ currentFunction = currentFunction[1:]
+ }
+ break
+ }
+ }
+ }
+
+ if strings.Contains(line, "OPENSSL_PUT_ERROR(") {
+ functionToken := prefix + "F_" + currentFunction
+ if _, ok := functions[functionToken]; !ok {
+ functions[functionToken] = -1
+ }
+ }
+
+ handleDeclareMacro(line, "_R_", "OPENSSL_DECLARE_ERROR_REASON(", reasons)
+ handleDeclareMacro(line, "_F_", "OPENSSL_DECLARE_ERROR_FUNCTION(", functions)
+
+ for len(line) > 0 {
+ i := strings.Index(line, prefix)
+ if i == -1 {
+ break
+ }
+
+ line = line[i:]
+ end := strings.IndexFunc(line, func(r rune) bool {
+ return !(r == '_' || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9'))
+ })
+ if end == -1 {
+ end = len(line)
+ }
+
+ var token string
+ token, line = line[:end], line[end:]
+
+ switch {
+ case strings.HasPrefix(token, reasonPrefix):
+ if _, ok := reasons[token]; !ok {
+ reasons[token] = -1
+ }
+ }
+ }
+ }
+
+ return scanner.Err()
+}
+
+func parseHeader(lib string, file io.Reader) (functions, reasons map[string]int, err error) {
+ functions = make(map[string]int)
+ reasons = make(map[string]int)
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ typ, key, value, ok := parseDefineLine(scanner.Text(), lib)
+ if !ok {
+ continue
+ }
+
+ switch typ {
+ case typeFunctions:
+ functions[key] = value
+ case typeReasons:
+ reasons[key] = value
+ default:
+ panic("internal error")
+ }
+ }
+
+ err = scanner.Err()
+ return
+}
+
+func main() {
+ flag.Parse()
+
+ if err := makeErrors(*resetFlag); err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+}