X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fxds%2Fxds-gdb.git;a=blobdiff_plain;f=main.go;h=b193676c7daf455462dba242a8028278c8253716;hp=1ada40e5d8126f9302ba1e6cfbfda6f83e9f0520;hb=b79e2a08a58bef2121463ecaa8e902be7850ccc7;hpb=88af0d2f2fd483029d1b4789248f58a214855d85 diff --git a/main.go b/main.go index 1ada40e..b193676 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,23 @@ -// xds-gdb: a wrapper on gdb tool for X(cross) Development System. +/* + * Copyright (C) 2017-2018 "IoT.bzh" + * Author Sebastien Douheret + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * xds-gdb: a wrapper on gdb tool for X(cross) Development System. + */ + package main import ( @@ -15,9 +34,9 @@ import ( "path" + common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib" "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - common "github.com/iotbzh/xds-common/golib" "github.com/joho/godotenv" ) @@ -39,11 +58,11 @@ var AppSubVersion = "unknown-dev" // Create logger var log = logrus.New() -var earlyLog = []string{} +var logFileInitial = path.Join(os.TempDir(), "xds-gdb.log") // Application details const ( - appCopyright = "Apache-2.0" + appCopyright = "Copyright (C) 2017-2018 IoT.bzh - Apache-2.0" defaultLogLevel = "warning" ) @@ -64,16 +83,32 @@ type EnvVar struct { func exitError(code syscall.Errno, f string, a ...interface{}) { err := fmt.Sprintf(f, a...) fmt.Fprintf(os.Stderr, err+"\n") + log.Debugf("Exit: code=%v, err=%s", code, err) + os.Exit(int(code)) } // main func main() { - var uri, prjID, rPath, logLevel, logFile, sdkid, confFile, gdbNative string + var agentURL, serverURL string + var prjID, rPath, logLevel, logFile, sdkid, confFile, gdbNative string var listProject bool var err error - uri = "localhost:8000" + // Init Logger and set temporary file and level for the 1st part + // IOW while XDS_LOGLEVEL and XDS_LOGFILE options are not parsed + logFile = logFileInitial + fdL, err := os.OpenFile(logFileInitial, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err != nil { + fmt.Printf("WARNING: Cannot create initial log file %s\n", logFileInitial) + log.Level = logrus.WarnLevel + } else { + log.Out = fdL + log.Level = logrus.DebugLevel + } + log.Formatter = &logrus.TextFormatter{} + + agentURL = "localhost:8800" logLevel = defaultLogLevel // Create a new App instance @@ -109,7 +144,7 @@ func main() { }, EnvVar{ Name: "XDS_LOGFILE", - Usage: "logging file", + Usage: "logging file (default: " + logFileInitial + ")", Destination: &logFile, }, EnvVar{ @@ -132,14 +167,20 @@ func main() { Usage: "Cross Sdk ID to use to build project", Destination: &sdkid, }, + EnvVar{ + Name: "XDS_AGENT_URL", + Usage: "local XDS agent url", + Destination: &agentURL, + }, EnvVar{ Name: "XDS_SERVER_URL", - Usage: "remote XDS server url", - Destination: &uri, + Usage: "overwrite remote XDS server url (default value set in xds-agent-config.json file)", + Destination: &serverURL, }, } // Process gdb arguments + log.Debugf("xds-gdb started with args: %v", os.Args) args := make([]string, len(os.Args)) args[0] = os.Args[0] gdbArgs := make([]string, len(os.Args)) @@ -149,7 +190,7 @@ func main() { for idx, a := range os.Args[1:] { // Specific case to print help or version of xds-gdb switch a { - case "--help", "-h", "--version", "-v": + case "--help", "-h", "--version", "-v", "--list", "-ls": args[1] = a goto endloop case "--": @@ -190,8 +231,13 @@ endloop: // Source config env file // (we cannot use confFile var because env variables setting is just after) envMap, confFile, err := loadConfigEnvFile(os.Getenv("XDS_CONFIG"), gdbCmdFile) - if err != nil { - exitError(syscall.ENOENT, err.Error()) + log.Infof("Load env config: envMap=%v, confFile=%v, err=%v", envMap, confFile, err) + + // Only rise an error when args is not set (IOW when --help or --version is not set) + if len(args) == 1 { + if err != nil { + exitError(syscall.ENOENT, err.Error()) + } } // Managed env vars and create help @@ -225,28 +271,29 @@ endloop: var err error curDir, _ := os.Getwd() - // Set logger level, formatter and log file + // Build env variables + env := []string{} + for k, v := range envMap { + env = append(env, k+"="+v) + } + + // Now set logger level and log file to correct/env var settings if log.Level, err = logrus.ParseLevel(logLevel); err != nil { msg := fmt.Sprintf("Invalid log level : \"%v\"\n", logLevel) return cli.NewExitError(msg, int(syscall.EINVAL)) } - log.Formatter = &logrus.TextFormatter{} + log.Infof("Switch log level to %s", logLevel) - // Always log into a file - if logFile == "" { - logFile = "/tmp/xds-gdb.log" - } - fdL, err := os.OpenFile(logFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) - if err != nil { - msgErr := fmt.Sprintf("Cannot create log file %s", logFile) - return cli.NewExitError(msgErr, int(syscall.EPERM)) - } - log.Out = fdL + if logFile != logFileInitial { + log.Infof("Switch logging to log file %s", logFile) - // Build env variables - env := []string{} - for k, v := range envMap { - env = append(env, k+"="+v) + fdL, err := os.OpenFile(logFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) + if err != nil { + msgErr := fmt.Sprintf("Cannot create log file %s", logFile) + return cli.NewExitError(msgErr, int(syscall.EPERM)) + } + defer fdL.Close() + log.Out = fdL } // Create cross or native gdb interface @@ -255,18 +302,14 @@ endloop: gdb = NewGdbNative(log, gdbArgs, env) } else { gdb = NewGdbXds(log, gdbArgs, env) - gdb.SetConfig("uri", uri) + gdb.SetConfig("agentURL", agentURL) + gdb.SetConfig("serverURL", serverURL) gdb.SetConfig("prjID", prjID) gdb.SetConfig("sdkID", sdkid) gdb.SetConfig("rPath", rPath) gdb.SetConfig("listProject", listProject) } - // Log early print - for _, msg := range earlyLog { - log.Debugf(msg) - } - // Log useful info log.Infof("Original arguments: %v", os.Args) log.Infof("Current directory : %v", curDir) @@ -298,7 +341,13 @@ endloop: }) gdb.OnDisconnect(func(err error) { - fmt.Println("Disconnection: ", err.Error()) + errMsg := "\nXDS-Agent disconnected" + if err != nil { + fmt.Printf("%s: %v\n", errMsg, err.Error()) + } else { + fmt.Println(errMsg) + } + exitChan <- exitResult{err, int(syscall.ESHUTDOWN)} }) @@ -308,8 +357,14 @@ endloop: log.Debugf("Recv OUT: <%s>", stdout) } if stderr != "" { - fmt.Fprintf(os.Stderr, "%s", stderr) - log.Debugf("Recv ERR: <%s>", stderr) + // Filter-out ugly message (python error when cross gdb exited) + if !strings.Contains(stderr, "readline.write_history_file") && + !(strings.Contains(stderr, "Traceback") && strings.Contains(stderr, "__exithandler")) { + fmt.Fprintf(os.Stderr, "%s", stderr) + log.Debugf("Recv ERR: <%s>", stderr) + } else { + log.Debugf("Recv ERR (FILTERED OUT): <%s>", stderr) + } } // Correctly report error about init file @@ -329,7 +384,7 @@ endloop: // Handle client tty / pts if clientPty != "" { - log.Infoln("Client tty detected: %v\n", clientPty) + log.Infoln("Client tty detected: %v", clientPty) cpFd, err := os.OpenFile(clientPty, os.O_RDWR, 0) if err != nil { @@ -344,7 +399,7 @@ endloop: sc := bufio.NewScanner(reader) for sc.Scan() { data := sc.Text() - iosk.Emit(apiv1.ExecInferiorInEvent, data+"\n") + iosk.Emit(xaapiv1.ExecInferiorInEvent, data+"\n") log.Debugf("Inferior IN: <%v>", data) } if sc.Err() != nil { @@ -393,6 +448,10 @@ endloop: paranoia := 600 reader := bufio.NewReader(os.Stdin) + // Enable workaround to correctly close connection + // except if XDS_GDBSERVER_EXIT_NOFIX is defined + _, gdbExitNoFix := os.LookupEnv("XDS_GDBSERVER_EXIT_NOFIX") + for { sc := bufio.NewScanner(reader) for sc.Scan() { @@ -405,8 +464,18 @@ endloop: log.Debugf("OVERWRITE %s -> %s", key, value) } } - gdb.Write(command + "\n") + + // Send SIGINT to stop debugged process execution before sending -gdb-exit command + if !gdbExitNoFix && strings.Contains(command, "-gdb-exit") { + log.Infof("Detection of -gdb-exit, exiting...") + if err := gdb.SendSignal(syscall.SIGINT); err != nil { + log.Errorf("Error while sending signal SIGINT : %s", err.Error()) + } + time.Sleep(time.Millisecond * 200) + } + log.Debugf("Send: <%v>", command) + gdb.Write(command + "\n") } log.Infof("Stdin scanner exit, close stdin (err=%v)", sc.Err()) @@ -430,8 +499,13 @@ endloop: go func() { for { sig := <-sigs + + if isIgnoredSignal(sig) { + return + } + if err := gdb.SendSignal(sig); err != nil { - log.Errorf("Error while sending signal: %s", err.Error()) + log.Errorf("Error while sending signal %v : %s", sig, err.Error()) } } }() @@ -467,13 +541,13 @@ func loadConfigEnvFile(confFile, gdbCmdFile string) (map[string]string, string, // 1- if no confFile set, use setting from gdb command file is option // --command/-x is set if confFile == "" && gdbCmdFile != "" { - logEarly("Try extract config from gdbCmdFile: %s", gdbCmdFile) + log.Infof("Try extract config from gdbCmdFile: %s", gdbCmdFile) confFile, err = extractEnvFromCmdFile(gdbCmdFile) if confFile != "" { defer os.Remove(confFile) } if err != nil { - return envMap, confFile, fmt.Errorf(err.Error()) + log.Infof("Extraction from gdbCmdFile failed: %v", err.Error()) } } // 2- search xds-gdb.env file in various locations @@ -483,13 +557,14 @@ func loadConfigEnvFile(confFile, gdbCmdFile string) (map[string]string, string, xdsEnvFile := "xds-gdb.env" for _, d := range []string{ path.Join(curDir), - path.Join(curDir, "..", ".."), - path.Join(curDir, "../../target"), - path.Join(u.HomeDir, ".xds"), + path.Join(curDir, ".."), + path.Join(curDir, "target"), + path.Join(u.HomeDir, ".config", "xds"), } { - confFile = path.Join(d, xdsEnvFile) - logEarly("Search config in %s", confFile) - if common.Exists(confFile) { + cf := path.Join(d, xdsEnvFile) + log.Infof("Search config in %s", cf) + if common.Exists(cf) { + confFile = cf break } } @@ -497,6 +572,7 @@ func loadConfigEnvFile(confFile, gdbCmdFile string) (map[string]string, string, } if confFile == "" { + log.Infof("NO valid conf file found!") return envMap, "", nil } @@ -509,6 +585,7 @@ func loadConfigEnvFile(confFile, gdbCmdFile string) (map[string]string, string, if envMap, err = godotenv.Read(confFile); err != nil { return envMap, confFile, fmt.Errorf("Error reading env config file " + confFile) } + return envMap, confFile, nil } @@ -517,9 +594,9 @@ func loadConfigEnvFile(confFile, gdbCmdFile string) (map[string]string, string, All commented lines (#) in gdb command file that start with ':XDS-ENV:' prefix will be considered as XDS env commands. For example the 3 syntaxes below are supported: - # :XDS-ENV: XDS_PROJECT_ID=IW7B4EE-DBY4Z74_myProject - #:XDS-ENV:XDS_SDK_ID=poky-agl_aarch64_3.99.1+snapshot - # :XDS-ENV: export XDS_SERVER_URL=localhost:8800 + # :XDS-ENV: XDS_PROJECT_ID=4021617e-ced0-11e7-acd2-3c970e49ad9b + #:XDS-ENV:XDS_SDK_ID=06c0e95a-e215-3a5a-b373-f677c0dabd3b + # :XDS-ENV: export XDS_AGENT_URL=localhost:8800 */ func extractEnvFromCmdFile(cmdFile string) (string, error) { if !common.Exists(cmdFile) { @@ -572,7 +649,3 @@ func extractEnvFromCmdFile(cmdFile string) (string, error) { return envFileName, nil } - -func logEarly(format string, a ...interface{}) { - earlyLog = append(earlyLog, fmt.Sprintf(format, a...)) -}