static int UppOneSimplify(VarItem &varItem, int step) { // setup item type varItem.kind = VarItem::COMPLEX; // if we're just doing first scan phase, signal that we need further evaluation later #ifdef EVALDEEP if(!step) // next step is 1 return 1; #else varItem.value = placeHolder; return 0; #endif // de-reference and forward simplify MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + "." + "ptr"); if(val.IsError() || !val.IsString()) { varItem.value = "Upp::One<> = <can't evaluate contents>"; return 0; } String ptr = val.ToString(); if(ptr == "0x0") { varItem.value = "Upp::One<> = <EMPTY>"; return 0; } // replace variable with de-referenced one VarItem vItem(&varItem.Debugger(), "*" + varItem.evaluableExpression + "." + "ptr"); varItem = vItem; return varItem.GetSimplifyStep(); }
bool Gdb_MI2::SetBreakpoint(const String& filename, int line, const String& bp) { String file = Filter(host->GetHostPath(NormalizePath(filename)), CharFilterReSlash2); // gets all breakpoints MIValue bps = GetBreakpoints(); // line should start from 1... line++; // check wether we've got already a breakpoint here // and remove it MIValue brk = pick(bps.FindBreakpoint(file, line)); if(!brk.IsEmpty()) if(!MICmd(Format("break-delete %s", brk["number"].Get()))) { Exclamation(t_("Couldn't remove breakpoint")); return false; } if(bp.IsEmpty()) return true; else if(bp[0] == 0xe) return MICmd(Format("break-insert %s:%d", file, line)); else return MICmd(Format("break-insert -c \"%s\" %s:%d", bp, file, line)); }
static int UppDateSimplify(VarItem &varItem, int step) { MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression); val.PackNames(); int day = atoi(val["day"].ToString()); int month = atoi(val["month"].ToString()); int year = atoi(val["year"].ToString()); varItem.value = Format("Upp::Date = %02d/%02d/%04d", day, month, year); return 0; }
static int UppTimeSimplify(VarItem &varItem, int step) { MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression); val.PackNames(); int day = atoi(val[0]["day"].ToString()); int month = atoi(val[0]["month"].ToString()); int year = atoi(val[0]["year"].ToString()); int hour = atoi(val["hour"].ToString()); int minute = atoi(val["minute"].ToString()); int second = atoi(val["second"].ToString()); varItem.value = Format("Upp::Time = %02d/%02d/%04d - %02d:%02d:%02d", day, month, year, hour, minute, second); return 0; }
MIValue &MIValue::FindAdd(String const &key, String const &data) { if(IsEmpty()) { Clear(); type = MITuple; } if(type != MITuple) return ErrorMIValue("Not a Tuple value type"); int idx = tuple.Find(key); MIValue v; v.Set(data); if(idx >= 0) tuple[idx] = pick(v); else tuple.AddPick(key, pick(v)); return *this; }
int MIValue::ParseArray(String const &s, int i) { Clear(); type = MIArray; // drop opening delimiter if(!expect("ParseArray", '[', i, s)) return s.GetCount(); i++; while(s[i] && isspace(s[i])) i++; while(s[i] && s[i] != ']') { while(s[i] && isspace(s[i])) i++; String name; MIValue val; if(s[i] == '[') i = val.ParseArray(s, i); else if(s[i] == '{') i = val.ParseTuple(s, i); else if(s[i] == '"') i = val.ParseString(s, i); else if(s[i] == '<') i = val.ParseAngle(s, i); else i = ParsePair(name, val, s, i); array.Add() = pick(val); while(s[i] && isspace(s[i])) i++; if(s[i] == ']') break; if(!expect("ParseArray", ',', i, s)) return s.GetCount(); i++; } return i + 1; }
static int UppStringSimplify(VarItem &varItem, int step) { enum { SMALL = 0, MEDIUM = 31 }; // SMALL has to be 0 because of GetSpecial and because is it ending zero enum { KIND = 14, SLEN = 15, LLEN = 2, SPECIAL = 13 }; union { char chr[16]; char *ptr; dword *wptr; qword *qptr; word v[8]; dword w[4]; qword q[2]; } u; // see Upp::String code for how it works.... MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ")." + "chr"); if(!val.IsString()) return 0; String chrs = val.ToString(); memcpy(u.chr, ~chrs, 16); bool isSmall = (u.chr[14] == 0); String s; if(isSmall) { byte len = u.chr[SLEN]; s = chrs.Left(len); } else { dword len = u.w[LLEN]; MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ").ptr[0]@" + FormatInt(len)); if(!val.IsString()) return 0; s = val.ToString(); } varItem.value = "\"" + s + "\""; varItem.kind = VarItem::SIMPLE; return 0; }
MIValue &MIValue::Add(String const &data) { MIValue v; v.Set(data); return Add(v); }
int MIValue::ParsePair(String &name, MIValue &val, String const &s, int i) { name.Clear(); val.Clear(); while(s[i] && isspace(s[i])) i++; if(!s[i]) { SetError("ParsePair:Unexpected end of string"); return i; } // is starting wirh '[' or '{' take it as a value with empty name if(s[i] == '{' || s[i] == '[') { name = "<UNNAMED>"; return val.ParseTuple(s, i); } else { int aCount = 0; while(s[i] && ((s[i] != '=' && s[i] != '}' && s[i] != ']' && s[i] != ',') || aCount)) { if(s[i] == '<') aCount++; else if(s[i] == '>') aCount--; if(s[i] == '\\') name.Cat(backslash(s, i)); else name.Cat(s[i]); i++; // skip blanks if not inside <> /* if(!aCount) while(s[i] && isspace(s[i])) i++; */ } while(s[i] && isspace(s[i])) i++; if(s[i] != '=') { // we take the data without = as the value part // of keyless tuple... val.Set(name); name = "<UNNAMED>"; return i; } i++; while(s[i] && isspace(s[i])) i++; } // skip address part before a tuple start, if any... it's useless and confuses the parser if(s[i] == '@') { int j = i; while(s[j] && s[j] != ':') j++; if(s[j] == ':') j++; while(s[j] && IsSpace(s[j])) j++; if(s[j] == '{') i = j; } switch(s[i]) { case '"': i = val.ParseString(s, i); break; break; case '[': i = val.ParseArray(s, i); break; case '{': i = val.ParseTuple(s, i); break; default: i = val.ParseUnquotedString(s, i); break; } return i; }
static MIValue &ErrorMIValue(String const &msg) { static MIValue v; v.SetError(msg); return v; }
// read debugger output analyzing command responses and async output // things are quite tricky because debugger output seems to be // slow and we have almost no terminator to stop on -- (gdb) is not // so reliable as it can happen (strangely) in middle of nothing MIValue Gdb_MI2::ParseGdb(String const &output, bool wait) { MIValue res; // parse result data StringStream ss(output); while(!ss.IsEof()) { String s; String str = ss.GetLine(); s = str; while(str.GetCount() == 1024 && !ss.IsEof()) { str = ss.GetLine(); s << str; } s = TrimBoth(s); // check 'running' and 'stopped' async output if(s.StartsWith("*running")) { started = true; stopReason.Clear(); continue; } else if(s.StartsWith("*stopped")) { stopped = true; s = '{' + s.Mid(9) + '}'; stopReason = MIValue(s); continue; } // catch process start/stop and store/remove pids else if(s.StartsWith("=thread-group-started,id=")) { String id, pid; int i = s.Find("id="); if(i < 0) continue; i += 4; while(s[i] && s[i] != '"') id.Cat(s[i++]); i = s.Find("pid="); if(i < 0) continue; i += 5; while(s[i] && s[i] != '"') pid.Cat(s[i++]); processes.Add(id, atoi(pid)); continue; } else if(s.StartsWith("=thread-group-exited,id=")) { String id; int i = s.Find("id="); if(i < 0) continue; i += 4; while(s[i] && s[i] != '"') id.Cat(s[i++]); i = processes.Find(id); if(i >= 0) processes.Remove(i); continue; } // skip asynchronous responses // in future, we could be gather/use them if(s[0] == '*'|| s[0] == '=') continue; // here handling of command responses // we're not interested either, as we use MI interface if(s[0] == '~') continue; // here handling of target output // well, for now discard this one too, but it should go on console output if(s[0] == '~') continue; // here handling of gdb log/debug message // not interesting here if(s[0] == '&') continue; // now we SHALL have something starting with any of // // "^done", "^running", "^connected", "^error" or "^exit" records if(s.StartsWith("^done") || s.StartsWith("^running")) { // here we've got succesful command output in list form, if any // shall skip the comma; following can be a serie of pairs, // or directly an array of maps in form of : // [{key="value",key="value",...},{key="value"...}...] int i = 5; // just skip shortest, ^done while(s[i] && s[i] != ',') i++; if(!s[i]) continue; i++; if(!s[i]) continue; res = MIValue(s.Mid(i)); continue; } else if(s.StartsWith("^error")) { // first array element is reserved for command result status s = s.Right(12); // '^error,msg=\"' s = s.Left(s.GetCount() - 1); res.SetError(s); } else continue; } return res; }
static int UppVectorSimplify(VarItem &varItem, int step) { // setup item type varItem.kind = VarItem::ARRAY; // if we're just doing first scan phase, signal that we need further evaluation later #ifdef EVALDEEP if(!step) // next step is 1 return 1; #else varItem.value = placeHolder; return 0; #endif // just getting items count... if(step == 1) { // initialize default value varItem.value = "<can't evaluate>"; // get items count MIValue val = varItem.EvaluateExpression(varItem.evaluableExpression + ".items"); if(val.IsError() || !val.IsString()) return 0; varItem.items = atoi(val.ToString()); // update value varItem.value = Format("Upp::Vector with %d elements", varItem.items, ""); // if no elements, just quit if(!varItem.items) return 0; return 2; } int count = min(EVALDEEP_VECTOR, varItem.items); // start from item 0 step -= 2; // fetch elements, check on first if they're SIMPLE, so displayable VarItem vItem(&varItem.Debugger(), varItem.evaluableExpression + Format(".vector[%d]", step)); if(!vItem) { varItem.value << " <can't evaluate contents>"; return 0; } if(vItem.kind != VarItem::SIMPLE) { varItem.value << " = [...]"; return 0; } vItem.Simplify(); if(!step) varItem.value << " = [ ]"; const char *sep = step ? " , " : ""; varItem.value = varItem.value.Left(varItem.value.GetCount() - 2) + sep + vItem.value + " ]"; if(++step >= count) return 0; else return step + 2; }
static int UppValueSimplify(VarItem &varItem, int step) { enum { SMALL = 0, MEDIUM = 31 }; // SMALL has to be 0 because of GetSpecial and because is it ending zero enum { KIND = 14, SLEN = 15, LLEN = 2, SPECIAL = 13 }; enum { STRING = 0, REF = 255, VOIDV = 3 }; // get the embedded 'data' string 'chr' member // it contains info about value type union { char chr[16]; char *ptr; dword *wptr; qword *qptr; word v[8]; dword w[4]; qword q[2]; int iData; int64 i64Data; double dData; bool bData; struct { byte day; byte month; int16 year; byte hour; byte minute; byte second; }; } u; // see Upp::String code for how it works.... MIValue val = varItem.EvaluateExpression("(" + varItem.evaluableExpression + ").data.chr"); if(!val.IsString()) return 0; String chrs = val.ToString(); memcpy(u.chr, ~chrs, 16); // get value type, among the fixed ones // we could try later to decode registered types.... dword type; bool isSpecial = !u.v[7] && u.v[6]; if(!isSpecial) type = STRING_V; else { byte st = u.chr[SPECIAL]; if(st == REF) { // ptr()->GetType() // by now, just mark as ref... type = REF; } else if(st == VOIDV) type = VOID_V; else type = st; } // by now, treat all types beyond VALUEMAP_V as unknown if(type > VALUEMAP_V) type = UNKNOWN_V; // now, based on type, we can decode it varItem.kind = VarItem::SIMPLE; switch(type) { case VOID_V: { varItem.value = "<VOID>"; return 0; } case INT_V: { varItem.value = FormatInt(u.iData); return 0; } case DOUBLE_V: { varItem.value = FormatDouble(u.dData); return 0; } case STRING_V: { // we simply replace the VarItem with the string VarItem vItem(&varItem.Debugger(), "(" + varItem.evaluableExpression + ").data"); vItem.evaluableExpression = varItem.evaluableExpression; vItem.shortExpression = varItem.shortExpression; varItem = vItem; return 0; } case DATE_V: { varItem.value = Format("Upp::Date = %02d/%02d/%04d", u.day, u.month, u.year); return 0; } case TIME_V: { varItem.value = Format("Upp::Time = %02d/%02d/%04d - %02d:%02d:%02d", u.day, u.month, u.year, u.hour, u.minute, u.second); return 0; } break; case ERROR_V: { varItem.value = "<ERROR_V>"; return 0; } case VALUE_V: { varItem.value = "<VALUE_V>"; return 0; } case WSTRING_V: { varItem.value = "<WSTRING_V>"; return 0; } case VALUEARRAY_V: { varItem.value = "<VALUEARRAY_V>"; return 0; } case INT64_V: { varItem.value = FormatInt64(u.i64Data); return 0; } case BOOL_V: { varItem.value = (u.bData ? "TRUE" : "FALSE"); return 0; } case VALUEMAP_V: { varItem.value = "<VALUEMAP_V>"; return 0; } case UNKNOWN_V: default: { varItem.value = "<UNKNOWN_V>"; return 0; } } }