X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=gdb-xds.go;h=981b977eb83544c1d3426085b45c95010a144833;hb=26e08d45599deb4ade79e0ca45a97196f2bd7da9;hp=e663714a45e7928f5ecc0319d991df2db322a6de;hpb=85b98b57b4543a84673daff52b52592c5bd5347d;p=src%2Fxds%2Fxds-gdb.git diff --git a/gdb-xds.go b/gdb-xds.go index e663714..981b977 100644 --- a/gdb-xds.go +++ b/gdb-xds.go @@ -3,17 +3,16 @@ package main import ( "encoding/json" "fmt" - "net/http" "os" + "regexp" + "strconv" "strings" "syscall" "github.com/Sirupsen/logrus" + "github.com/iotbzh/xds-agent/lib/xaapiv1" common "github.com/iotbzh/xds-common/golib" - "github.com/iotbzh/xds-server/lib/apiv1" - "github.com/iotbzh/xds-server/lib/crosssdk" - "github.com/iotbzh/xds-server/lib/xdsconfig" - sio_client "github.com/zhouhui8915/go-socket.io-client" + sio_client "github.com/sebd71/go-socket.io-client" ) // GdbXds - @@ -28,10 +27,13 @@ type GdbXds struct { rPath string listPrj bool cmdID string + xGdbPid string httpCli *common.HTTPClient ioSock *sio_client.Client + projects []xaapiv1.ProjectConfig + // callbacks cbOnError func(error) cbOnDisconnect func(error) @@ -49,6 +51,7 @@ func NewGdbXds(log *logrus.Logger, args []string, env []string) *GdbXds { eenv: env, httpCli: nil, ioSock: nil, + xGdbPid: strconv.Itoa(os.Getpid()), } } @@ -74,6 +77,9 @@ func (g *GdbXds) SetConfig(name string, value interface{}) error { // Init initializes gdb XDS func (g *GdbXds) Init() (int, error) { + // Reset command ID (also used to enable sending of signals) + g.cmdID = "" + // Define HTTP and WS url baseURL := g.uri if !strings.HasPrefix(g.uri, "http://") { @@ -84,25 +90,50 @@ func (g *GdbXds) Init() (int, error) { g.log.Infoln("Connect HTTP client on ", baseURL) conf := common.HTTPClientConfig{ URLPrefix: "/api/v1", - HeaderClientKeyName: "XDS-SID", + HeaderClientKeyName: "Xds-Agent-Sid", CsrfDisable: true, + LogOut: g.log.Out, + LogLevel: common.HTTPLogLevelWarning, } c, err := common.HTTPNewClient(baseURL, conf) if err != nil { - return int(syscallEBADE), err + errmsg := err.Error() + if m, err := regexp.MatchString("Get http.?://", errmsg); m && err == nil { + i := strings.LastIndex(errmsg, ":") + errmsg = "Cannot connection to " + baseURL + errmsg[i:] + } + return int(syscallEBADE), fmt.Errorf(errmsg) } g.httpCli = c + g.httpCli.SetLogLevel(g.log.Level.String()) + g.log.Infoln("HTTP session ID:", g.httpCli.GetClientID()) + + // First call to check that xds-agent and server are alive + ver := xaapiv1.XDSVersion{} + if err := g.httpCli.Get("/version", &ver); err != nil { + return int(syscallEBADE), err + } + g.log.Infoln("XDS agent & server version:", ver) - // First call to check that xds-server is alive + // SEB Check that server is connected + // FIXME: add multi-servers support + + // Get XDS projects list var data []byte - if err := c.HTTPGet("/folders", &data); err != nil { + if err := g.httpCli.HTTPGet("/projects", &data); err != nil { return int(syscallEBADE), err } - g.log.Infof("Result of /folders: %v", string(data[:])) + + g.log.Infof("Result of /projects: %v", string(data[:])) + g.projects = []xaapiv1.ProjectConfig{} + errMar := json.Unmarshal(data, &g.projects) + if errMar != nil { + g.log.Errorf("Cannot decode projects configuration: %s", errMar.Error()) + } // Check mandatory args if g.prjID == "" || g.listPrj { - return getProjectsList(c, g.log, data) + return g.printProjectsList() } // Create io Websocket client @@ -112,7 +143,7 @@ func (g *GdbXds) Init() (int, error) { Transport: "websocket", Header: make(map[string][]string), } - opts.Header["XDS-SID"] = []string{c.GetClientID()} + opts.Header["XDS-AGENT-SID"] = []string{c.GetClientID()} iosk, err := sio_client.NewClient(baseURL, opts) if err != nil { @@ -133,19 +164,19 @@ func (g *GdbXds) Init() (int, error) { } }) - iosk.On(apiv1.ExecOutEvent, func(ev apiv1.ExecOutMsg) { + iosk.On(xaapiv1.ExecOutEvent, func(ev xaapiv1.ExecOutMsg) { if g.cbRead != nil { g.cbRead(ev.Timestamp, ev.Stdout, ev.Stderr) } }) - iosk.On(apiv1.ExecInferiorOutEvent, func(ev apiv1.ExecOutMsg) { + iosk.On(xaapiv1.ExecInferiorOutEvent, func(ev xaapiv1.ExecOutMsg) { if g.cbInferiorRead != nil { g.cbInferiorRead(ev.Timestamp, ev.Stdout, ev.Stderr) } }) - iosk.On(apiv1.ExecExitEvent, func(ev apiv1.ExecExitMsg) { + iosk.On(xaapiv1.ExecExitEvent, func(ev xaapiv1.ExecExitMsg) { if g.cbOnExit != nil { g.cbOnExit(ev.Code, ev.Error) } @@ -154,26 +185,53 @@ func (g *GdbXds) Init() (int, error) { return 0, nil } +// Close frees allocated objects and close opened connections func (g *GdbXds) Close() error { g.cbOnDisconnect = nil g.cbOnError = nil g.cbOnExit = nil g.cbRead = nil g.cbInferiorRead = nil + g.cmdID = "" return nil } // Start sends a request to start remotely gdb within xds-server func (g *GdbXds) Start(inferiorTTY bool) (int, error) { - var body []byte var err error + var project *xaapiv1.ProjectConfig + + // Retrieve the project definition + for _, f := range g.projects { + // check as prefix to support short/partial id name + if strings.HasPrefix(f.ID, g.prjID) { + project = &f + break + } + } + + // Auto setup rPath if needed + if g.rPath == "" && project != nil { + cwd, err := os.Getwd() + if err == nil { + fldRp := project.ClientPath + if !strings.HasPrefix(fldRp, "/") { + fldRp = "/" + fldRp + } + log.Debugf("Try to auto-setup rPath: cwd=%s ; ClientPath=%s", cwd, fldRp) + if sp := strings.SplitAfter(cwd, fldRp); len(sp) == 2 { + g.rPath = strings.Trim(sp[1], "/") + g.log.Debugf("Auto-setup rPath to: '%s'", g.rPath) + } + } + } // Enable workaround about inferior output with gdbserver connection // except if XDS_GDBSERVER_OUTPUT_NOFIX is defined _, gdbserverNoFix := os.LookupEnv("XDS_GDBSERVER_OUTPUT_NOFIX") - args := apiv1.ExecArgs{ + args := xaapiv1.ExecArgs{ ID: g.prjID, SdkID: g.sdkID, Cmd: g.ccmd, @@ -184,24 +242,17 @@ func (g *GdbXds) Start(inferiorTTY bool) (int, error) { TTYGdbserverFix: !gdbserverNoFix, CmdTimeout: -1, // no timeout, end when stdin close or command exited normally } - body, err = json.Marshal(args) - if err != nil { - return int(syscallEBADE), err - } - g.log.Infof("POST %s/exec %v", g.uri, string(body)) - var res *http.Response - var found bool - res, err = g.httpCli.HTTPPostWithRes("/exec", string(body)) + g.log.Infof("POST %s/exec %v", g.uri, args) + res := xaapiv1.ExecResult{} + err = g.httpCli.Post("/exec", args, &res) if err != nil { return int(syscall.EAGAIN), err } - dRes := make(map[string]interface{}) - json.Unmarshal(g.httpCli.ResponseToBArray(res), &dRes) - if _, found = dRes["cmdID"]; !found { - return int(syscallEBADE), err + if res.CmdID == "" { + return int(syscallEBADE), fmt.Errorf("null CmdID") } - g.cmdID = dRes["cmdID"].(string) + g.cmdID = res.CmdID return 0, nil } @@ -248,34 +299,31 @@ func (g *GdbXds) InferiorRead(f func(timestamp, stdout, stderr string)) { // Write writes message/string into gdb stdin func (g *GdbXds) Write(args ...interface{}) error { - return g.ioSock.Emit(apiv1.ExecInEvent, args...) + return g.ioSock.Emit(xaapiv1.ExecInEvent, args...) } // SendSignal is used to send a signal to remote process/gdb func (g *GdbXds) SendSignal(sig os.Signal) error { - var body []byte - body, err := json.Marshal(apiv1.ExecSignalArgs{ + if g.cmdID == "" { + return fmt.Errorf("cmdID not set") + } + + sigArg := xaapiv1.ExecSignalArgs{ CmdID: g.cmdID, Signal: sig.String(), - }) - if err != nil { - g.log.Errorf(err.Error()) } - g.log.Debugf("POST /signal %s", string(body)) - return g.httpCli.HTTPPost("/signal", string(body)) + g.log.Debugf("POST /signal %v", sigArg) + return g.httpCli.Post("/signal", sigArg, nil) } //***** Private functions ***** -func getProjectsList(c *common.HTTPClient, log *logrus.Logger, prjData []byte) (int, error) { - - folders := xdsconfig.FoldersConfig{} - errMar := json.Unmarshal(prjData, &folders) +func (g *GdbXds) printProjectsList() (int, error) { msg := "" - if errMar == nil { + if len(g.projects) > 0 { msg += "List of existing projects (use: export XDS_PROJECT_ID=<< ID >>): \n" msg += " ID\t\t\t\t | Label" - for _, f := range folders { + for _, f := range g.projects { msg += fmt.Sprintf("\n %s\t | %s", f.ID, f.Label) if f.DefaultSdk != "" { msg += fmt.Sprintf("\t(default SDK: %s)", f.DefaultSdk) @@ -284,27 +332,22 @@ func getProjectsList(c *common.HTTPClient, log *logrus.Logger, prjData []byte) ( msg += "\n" } - var data []byte - if err := c.HTTPGet("/sdks", &data); err != nil { + // FIXME : support multiple servers + sdks := []xaapiv1.SDK{} + if err := g.httpCli.Get("/servers/0/sdks", &sdks); err != nil { return int(syscallEBADE), err } - log.Infof("Result of /sdks: %v", string(data[:])) - - sdks := []crosssdk.SDK{} - errMar = json.Unmarshal(data, &sdks) - if errMar == nil { - msg += "\nList of installed cross SDKs (use: export XDS_SDK_ID=<< ID >>): \n" - msg += " ID\t\t\t\t\t | NAME\n" - for _, s := range sdks { - msg += fmt.Sprintf(" %s\t | %s\n", s.ID, s.Name) - } + msg += "\nList of installed cross SDKs (use: export XDS_SDK_ID=<< ID >>): \n" + msg += " ID\t\t\t\t\t | NAME\n" + for _, s := range sdks { + msg += fmt.Sprintf(" %s\t | %s\n", s.ID, s.Name) } - if len(folders) > 0 && len(sdks) > 0 { + if len(g.projects) > 0 && len(sdks) > 0 { msg += fmt.Sprintf("\n") msg += fmt.Sprintf("For example: \n") msg += fmt.Sprintf(" XDS_PROJECT_ID=%q XDS_SDK_ID=%q %s -x myGdbConf.ini\n", - folders[0].ID, sdks[0].ID, AppName) + g.projects[0].ID, sdks[0].ID, AppName) } return 0, fmt.Errorf(msg)