github.com/transparency-dev/armored-witness-os@v0.1.3-0.20240514084412-27eef7325168/trusted_os/debug.go (about)

     1  // Copyright 2022 The Armored Witness OS authors. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build debug
    16  // +build debug
    17  
    18  package main
    19  
    20  import (
    21  	"bytes"
    22  	"debug/elf"
    23  	"debug/gosym"
    24  	"errors"
    25  	"fmt"
    26  	"log"
    27  	_ "unsafe"
    28  
    29  	"github.com/usbarmory/tamago/arm"
    30  	usbarmory "github.com/usbarmory/tamago/board/usbarmory/mk2"
    31  	"github.com/usbarmory/tamago/soc/nxp/usb"
    32  
    33  	"github.com/usbarmory/GoTEE/monitor"
    34  	usbserial "github.com/usbarmory/imx-usbserial"
    35  
    36  	"github.com/smallnest/ringbuffer"
    37  )
    38  
    39  const debug = true
    40  
    41  var serial *usbserial.UART
    42  var logBuffer *ringbuffer.RingBuffer
    43  
    44  func init() {
    45  	// TODO(al): Probably want to reinstate this check after wave0!
    46  	/*
    47  			if imx6ul.SNVS.Available() {
    48  			panic("fatal error, debug firmware not allowed on secure booted units")
    49  		}
    50  	*/
    51  	logBuffer = ringbuffer.New(1 << 20)
    52  }
    53  
    54  //go:linkname printk runtime.printk
    55  func printk(c byte) {
    56  	usbarmory.UART2.Tx(c)
    57  	logBuffer.WriteByte(c)
    58  
    59  	if serial != nil {
    60  		serial.WriteByte(c)
    61  	}
    62  }
    63  
    64  func getConsoleLogs() []byte {
    65  	return logBuffer.Bytes()
    66  }
    67  
    68  func configureUART(device *usb.Device) (err error) {
    69  	if LAN == nil {
    70  		return
    71  	}
    72  
    73  	serial = &usbserial.UART{
    74  		Device: device,
    75  	}
    76  
    77  	return serial.Init()
    78  }
    79  
    80  func fileLine(buf []byte, pc uint32) (s string) {
    81  	exe, err := elf.NewFile(bytes.NewReader(buf))
    82  
    83  	if err != nil {
    84  		return
    85  	}
    86  
    87  	addr := exe.Section(".text").Addr
    88  
    89  	lineTableData, err := exe.Section(".gopclntab").Data()
    90  
    91  	if err != nil {
    92  		return
    93  	}
    94  
    95  	lineTable := gosym.NewLineTable(lineTableData, addr)
    96  
    97  	if err != nil {
    98  		return
    99  	}
   100  
   101  	symTableData, err := exe.Section(".gosymtab").Data()
   102  
   103  	if err != nil {
   104  		return
   105  	}
   106  
   107  	symTable, err := gosym.NewTable(symTableData, lineTable)
   108  
   109  	if err != nil {
   110  		return
   111  	}
   112  
   113  	file, line, _ := symTable.PCToLine(uint64(pc))
   114  
   115  	return fmt.Sprintf("%s:%d", file, line)
   116  }
   117  
   118  func lookupSym(buf []byte, name string) (*elf.Symbol, error) {
   119  	f, err := elf.NewFile(bytes.NewReader(buf))
   120  
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	syms, err := f.Symbols()
   126  
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	for _, sym := range syms {
   132  		if sym.Name == name {
   133  			return &sym, nil
   134  		}
   135  	}
   136  
   137  	return nil, errors.New("symbol not found")
   138  }
   139  
   140  // segfault schedules the execution context to its fatal error function in
   141  // order to have applet dump its own stack trace and exit. The target must be a
   142  // GOOS=tamago applet which imports the runtime.CallOnG0 symbol, runtime.Exit
   143  // must be set to graceful termination.
   144  //
   145  // Example of required applet main statements:
   146  //
   147  // ```
   148  //
   149  //	func init() {
   150  //		runtime.Exit = applet.Exit
   151  //		...
   152  //	}
   153  //
   154  //	func main() {
   155  //		...
   156  //		runtime.CallOnG0()
   157  //	}
   158  //
   159  // ```
   160  func segfault(buf []byte, ctx *monitor.ExecCtx) (err error) {
   161  	var sym *elf.Symbol
   162  
   163  	if sym, err = lookupSym(taELF, "runtime.fatalthrow"); err != nil {
   164  		return fmt.Errorf("could not find runtime.fatalthrow symbol, %v", err)
   165  	}
   166  
   167  	ctx.R0 = uint32(ctx.ExceptionVector)
   168  	ctx.R1 = uint32(sym.Value)
   169  	ctx.R2 = 0
   170  	ctx.R3 = ctx.R15
   171  
   172  	if sym, err = lookupSym(taELF, "runtime.CallOnG0"); err != nil {
   173  		return fmt.Errorf("could not find runtime.CallOnG0 symbol, %v", err)
   174  	}
   175  
   176  	ctx.R15 = uint32(sym.Value)
   177  
   178  	log.Printf("SM invoking applet %s handler pc:%#.8x", arm.VectorName(ctx.ExceptionVector), ctx.R3)
   179  
   180  	err = ctx.Run()
   181  
   182  	log.Printf("SM applet stopped sp:%#.8x lr:%#.8x pc:%#.8x err:%v", ctx.R13, ctx.R14, ctx.R15, err)
   183  
   184  	return
   185  }
   186  
   187  func inspect(buf []byte, ctx *monitor.ExecCtx) (err error) {
   188  	log.Printf("PC\t%s", fileLine(buf, ctx.R15)) // PC
   189  	log.Printf("LR\t%s", fileLine(buf, ctx.R14)) // LR
   190  
   191  	switch ctx.ExceptionVector {
   192  	case arm.UNDEFINED, arm.PREFETCH_ABORT, arm.DATA_ABORT:
   193  		return segfault(buf, ctx)
   194  	}
   195  
   196  	return
   197  }