Index: Session.vim =================================================================== --- /dev/null +++ Session.vim @@ -0,0 +1,1648 @@ +let SessionLoad = 1 +if &cp | set nocp | endif +let s:cpo_save=&cpo +set cpo&vim +imap :vsplit +imap :split +imap :NERDTreeFind +map  :tabn +nmap gx NetrwBrowseX +nnoremap NetrwBrowseX :call netrw#NetrwBrowseX(expand(""),0) +map :vsplit +map :split +map :NERDTreeFind +let &cpo=s:cpo_save +unlet s:cpo_save +set autoindent +set background=dark +set backspace=2 +set cindent +set expandtab +set fileencodings=ucs-bom,utf-8,default,latin1 +set helplang=en +set hlsearch +set incsearch +set modelines=0 +set shiftwidth=4 +set showmatch +set tabstop=4 +set visualbell +set wildignore=*.pyc +set window=0 +let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0 +let v:this_session=expand(":p") +silent only +cd ~/p/llvm/tools/lldb +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +set shortmess=aoO +badd +1103 tools/lldb-mi/MICmdCmdExec.cpp +badd +1 source/Commands/CommandObjectProcess.cpp +badd +3276 source/Target/Target.cpp +badd +73 scripts/Python/finishSwigPythonLLDB.py +badd +209 tools/lldb-mi/MICmnMIValueList.cpp +badd +123 include/lldb/Target/Target.h +badd +80 include/lldb/Target/ProcessLaunchInfo.h +badd +1 source/Target/ABI.cpp +badd +63 source/Interpreter/OptionValueProperties.cpp +badd +1 source/Interpreter/Property.cpp +badd +1 source/Interpreter/OptionValue.cpp +badd +403 include/lldb/Interpreter/OptionValue.h +badd +1 include/lldb/Interpreter/Options.h +badd +1 include/lldb/lldb-types.h +badd +1 include/lldb/lldb-versioning.h +badd +1 include/lldb/lldb-python.h +badd +1 include/lldb/lldb-public.h +badd +1 include/lldb/lldb-private.h +badd +1 include/lldb/lldb-private-types.h +badd +1 include/lldb/lldb-private-log.h +badd +39 include/lldb/lldb-private-interfaces.h +badd +412 include/lldb/Interpreter/Args.h +badd +6 source/Commands/CommandObjectProcess.h +badd +1 include/lldb/Interpreter/CommandObject.h +badd +1 include/lldb/Interpreter/CommandObjectMultiword.h +badd +1 include/lldb/Interpreter/CommandObjectRegexCommand.h +badd +1 include/lldb/Interpreter/CommandOptionValidators.h +badd +1 include/lldb/Interpreter/CommandReturnObject.h +badd +1 include/lldb/Interpreter/CommandInterpreter.h +badd +1 source/Target/ProcessLaunchInfo.cpp +badd +146 source/Target/Process.cpp +badd +1 include/lldb/Target/Process.h +badd +1 include/lldb/Target/ProcessInfo.h +badd +2579 source/API/SBTarget.cpp +badd +896 include/lldb/API/SBTarget.h +badd +25 source/API/SBLaunchInfo.cpp +badd +187 include/lldb/API/SBLaunchInfo.h +badd +287 source/API/SBModule.cpp +badd +85 include/lldb/API/SBLineEntry.h +badd +87 tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +badd +40 tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +badd +1 source/Interpreter/CommandReturnObject.cpp +badd +1 source/Interpreter/CommandObjectRegexCommand.cpp +badd +1 test/tools/lldb-mi/TestMiInterpreterExec.py +badd +1 source/Interpreter/OptionValueArgs.cpp +badd +1 source/Interpreter/OptionGroupVariable.cpp +badd +1 source/Interpreter/OptionGroupPlatform.cpp +badd +106 include/lldb/Interpreter/Property.h +badd +82 source/Interpreter/OptionValueArray.cpp +badd +53 source/Interpreter/OptionValueArch.cpp +badd +48 source/Interpreter/OptionValueBoolean.cpp +badd +1 source/Interpreter/OptionValueChar.cpp +badd +226 source/Interpreter/OptionValueDictionary.cpp +badd +65 source/Interpreter/OptionValueEnumeration.cpp +badd +81 source/Interpreter/OptionValueFileSpec.cpp +badd +127 source/Interpreter/OptionValueFileSpecLIst.cpp +badd +46 source/Interpreter/OptionValueFormat.cpp +badd +78 source/Interpreter/OptionValueFormatEntity.cpp +badd +103 source/Interpreter/OptionValuePathMappings.cpp +badd +60 source/Interpreter/OptionValueRegex.cpp +badd +61 source/Interpreter/OptionValueSInt64.cpp +badd +122 source/Interpreter/OptionValueString.cpp +badd +66 source/Interpreter/OptionValueUInt64.cpp +badd +59 source/Interpreter/OptionValueUUID.cpp +badd +45 include/lldb/lldb-enumerations.h +badd +1 source/Target/ProcessInfo.cpp +badd +1 source/Target/FileAction.cpp +badd +3 test/tools/lldb-mi/child.log +args tools/lldb-mi/MICmdCmdExec.cpp +edit test/tools/lldb-mi/TestMiInterpreterExec.py +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 13 + 36) / 72) +exe 'vert 2resize ' . ((&columns * 58 + 36) / 72) +argglobal +enew +file NERD_tree_1 +setlocal autoindent +setlocal nobinary +setlocal bufhidden=hide +setlocal nobuflisted +setlocal buftype=nofile +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal cursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'nerdtree' +setlocal filetype=nerdtree +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal nomodifiable +setlocal nrformats=octal,hex +set number +setlocal nonumber +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline=%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''} +setlocal suffixesadd= +setlocal noswapfile +setlocal synmaxcol=3000 +if &syntax != 'nerdtree' +setlocal syntax=nerdtree +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal winfixwidth +setlocal nowrap +setlocal wrapmargin=0 +wincmd w +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:XCOMM,n:>,fb:- +setlocal commentstring=#%s +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'python' +setlocal filetype=python +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include=s*\\(from\\|import\\) +setlocal includeexpr=substitute(v:fname,'\\.','/','g') +setlocal indentexpr=GetPythonIndent(v:lnum) +setlocal indentkeys=0{,0},:,!^F,o,O,e,<:>,=elif,=except +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=pythoncomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd=.py +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'python' +setlocal syntax=python +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 74 - ((26 * winheight(0) + 20) / 40) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +74 +normal! 043l +wincmd w +2wincmd w +exe 'vert 1resize ' . ((&columns * 13 + 36) / 72) +exe 'vert 2resize ' . ((&columns * 58 + 36) / 72) +tabedit source/Commands/CommandObjectProcess.cpp +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 252 - ((21 * winheight(0) + 20) / 41) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +252 +normal! 081l +2wincmd w +tabedit include/lldb/lldb-enumerations.h +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 44 - ((13 * winheight(0) + 20) / 41) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +44 +normal! 019l +2wincmd w +tabedit source/Target/Process.cpp +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 31 + 36) / 72) +exe '2resize ' . ((&lines * 19 + 21) / 43) +exe '3resize ' . ((&lines * 20 + 21) / 43) +argglobal +enew +file NERD_tree_2 +setlocal autoindent +setlocal nobinary +setlocal bufhidden=hide +setlocal nobuflisted +setlocal buftype=nofile +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal cursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'nerdtree' +setlocal filetype=nerdtree +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal nomodifiable +setlocal nrformats=octal,hex +set number +setlocal nonumber +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline=%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''} +setlocal suffixesadd= +setlocal noswapfile +setlocal synmaxcol=3000 +if &syntax != 'nerdtree' +setlocal syntax=nerdtree +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal winfixwidth +setlocal nowrap +setlocal wrapmargin=0 +wincmd w +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 524 - ((9 * winheight(0) + 9) / 19) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +524 +normal! 0 +wincmd w +argglobal +edit include/lldb/Target/Process.h +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 419 - ((9 * winheight(0) + 10) / 20) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +419 +normal! 03l +wincmd w +2wincmd w +exe 'vert 1resize ' . ((&columns * 31 + 36) / 72) +exe '2resize ' . ((&lines * 19 + 21) / 43) +exe '3resize ' . ((&lines * 20 + 21) / 43) +tabedit include/lldb/Target/ProcessInfo.h +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 13 + 36) / 72) +exe '2resize ' . ((&lines * 19 + 21) / 43) +exe 'vert 2resize ' . ((&columns * 58 + 36) / 72) +exe '3resize ' . ((&lines * 20 + 21) / 43) +exe 'vert 3resize ' . ((&columns * 58 + 36) / 72) +argglobal +enew +file NERD_tree_14 +setlocal autoindent +setlocal nobinary +setlocal bufhidden=hide +setlocal nobuflisted +setlocal buftype=nofile +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal cursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'nerdtree' +setlocal filetype=nerdtree +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal nomodifiable +setlocal nrformats=octal,hex +set number +setlocal nonumber +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline=%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''} +setlocal suffixesadd= +setlocal noswapfile +setlocal synmaxcol=3000 +if &syntax != 'nerdtree' +setlocal syntax=nerdtree +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal winfixwidth +setlocal nowrap +setlocal wrapmargin=0 +wincmd w +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 161 - ((0 * winheight(0) + 9) / 19) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +161 +normal! 011l +wincmd w +argglobal +edit include/lldb/Target/ProcessLaunchInfo.h +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal noexpandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 232 - ((0 * winheight(0) + 10) / 20) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +232 +normal! 019l +wincmd w +2wincmd w +exe 'vert 1resize ' . ((&columns * 13 + 36) / 72) +exe '2resize ' . ((&lines * 19 + 21) / 43) +exe 'vert 2resize ' . ((&columns * 58 + 36) / 72) +exe '3resize ' . ((&lines * 20 + 21) / 43) +exe 'vert 3resize ' . ((&columns * 58 + 36) / 72) +tabedit source/Target/Target.cpp +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 3064 - ((20 * winheight(0) + 20) / 41) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +3064 +normal! 066l +2wincmd w +tabedit source/Commands/CommandObjectProcess.cpp +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 229 - ((25 * winheight(0) + 22) / 44) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +229 +normal! 08l +2wincmd w +tabedit source/Target/ProcessLaunchInfo.cpp +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 321 - ((7 * winheight(0) + 20) / 41) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +321 +normal! 0 +2wincmd w +tabedit source/Target/FileAction.cpp +set splitbelow splitright +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +argglobal +setlocal autoindent +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal cindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal colorcolumn= +setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal cryptmethod= +setlocal nocursorbind +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'cpp' +setlocal filetype=cpp +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=croql +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc=ccomplete#Complete +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norelativenumber +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck= +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'cpp' +setlocal syntax=cpp +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal noundofile +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 69 - ((1 * winheight(0) + 22) / 44) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +69 +normal! 0 +2wincmd w +tabnext 1 +if exists('s:wipebuf') + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 shortmess=filnxtToO +let s:sx = expand(":p:r")."x.vim" +if file_readable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &so = s:so_save | let &siso = s:siso_save +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : Index: lldb_fix_getcompiler_in_lldbtest.patch =================================================================== --- /dev/null +++ lldb_fix_getcompiler_in_lldbtest.patch @@ -0,0 +1,16 @@ +Index: test/lldbtest.py +=================================================================== +--- test/lldbtest.py (revision 228674) ++++ test/lldbtest.py (working copy) +@@ -1515,6 +1515,11 @@ + path = os.path.join(lldb_root_path, p) + if os.path.exists(path): + return path ++ ++ # Tries to find clang at the same folder as the lldb ++ path = os.path.join(os.path.dirname(self.lldbExec), "clang") ++ if os.path.exists(path): ++ return path + + return os.environ["CC"] + Index: lldb_remove_unused_var.patch =================================================================== --- /dev/null +++ lldb_remove_unused_var.patch @@ -0,0 +1,12 @@ +Index: source/Target/Target.cpp +=================================================================== +--- source/Target/Target.cpp (revision 228674) ++++ source/Target/Target.cpp (working copy) +@@ -1662,7 +1662,6 @@ + // module in the shared module cache. + if (m_platform_sp) + { +- FileSpec platform_file_spec; + error = m_platform_sp->GetSharedModule (module_spec, + module_sp, + &GetExecutableSearchPaths(), Index: patches/lldb_fix_abbreviation_aliases_help_tests.patch =================================================================== --- /dev/null +++ patches/lldb_fix_abbreviation_aliases_help_tests.patch @@ -0,0 +1,66 @@ +Index: test/functionalities/abbreviation/TestAbbreviations.py +=================================================================== +--- test/functionalities/abbreviation/TestAbbreviations.py (revision 226488) ++++ test/functionalities/abbreviation/TestAbbreviations.py (working copy) +@@ -34,7 +34,7 @@ + + # Only one matching command: execute it. + self.expect("h", +- startstr = "The following is a list of built-in, permanent debugger commands:") ++ startstr = "Debugger commands:") + + # Execute cleanup function during test tear down + def cleanup(): +Index: test/functionalities/alias/TestAliases.py +=================================================================== +--- test/functionalities/alias/TestAliases.py (revision 226488) ++++ test/functionalities/alias/TestAliases.py (working copy) +@@ -114,10 +114,10 @@ + self.expect ("help -a run", + substrs = [ "'run' is an abbreviation for 'process launch -c /bin/sh --'" ]) + +- self.expect ("help -a", ++ self.expect ("help", + substrs = [ 'run', 'process launch -c /bin/sh' ]) + +- self.expect ("help", matching=False, ++ self.expect ("help -a", matching=False, + substrs = [ "'run'", 'process launch -c /bin/sh' ]) + + self.expect ("run", +Index: test/help/TestHelp.py +=================================================================== +--- test/help/TestHelp.py (revision 226488) ++++ test/help/TestHelp.py (working copy) +@@ -16,18 +16,18 @@ + def test_simplehelp(self): + """A simple test of 'help' command and its output.""" + self.expect("help", +- startstr = 'The following is a list of built-in, permanent debugger commands') ++ startstr = 'Debugger commands:') + +- self.expect("help", matching=False, ++ self.expect("help -a", matching=False, + substrs = ['next']) + +- self.expect("help -a", matching=True, ++ self.expect("help", matching=True, + substrs = ['next']) + + def test_help_on_help(self): + """Testing the help on the help facility.""" + self.expect("help help", matching=True, +- substrs = ['--show-aliases', ++ substrs = ['--hide-aliases', + '--hide-user-commands']) + + def version_number_string(self): +@@ -97,7 +97,7 @@ + substrs = ['error: 0 is out of range, valid values must be between']) + # self.runCmd("settings set term-width 0") + self.expect("help", +- startstr = 'The following is a list of built-in, permanent debugger commands') ++ startstr = 'Debugger commands:') + + def test_help_breakpoint_set(self): + """Test that 'help breakpoint set' does not print out redundant lines of: Index: patches/lldb_fix_abbreviation_and_alias_tests.patch =================================================================== --- /dev/null +++ patches/lldb_fix_abbreviation_and_alias_tests.patch @@ -0,0 +1,30 @@ +Index: test/functionalities/abbreviation/TestAbbreviations.py +=================================================================== +--- test/functionalities/abbreviation/TestAbbreviations.py (revision 226488) ++++ test/functionalities/abbreviation/TestAbbreviations.py (working copy) +@@ -34,7 +34,7 @@ + + # Only one matching command: execute it. + self.expect("h", +- startstr = "The following is a list of built-in, permanent debugger commands:") ++ startstr = "Debugger commands:") + + # Execute cleanup function during test tear down + def cleanup(): +Index: test/functionalities/alias/TestAliases.py +=================================================================== +--- test/functionalities/alias/TestAliases.py (revision 226488) ++++ test/functionalities/alias/TestAliases.py (working copy) +@@ -114,10 +114,10 @@ + self.expect ("help -a run", + substrs = [ "'run' is an abbreviation for 'process launch -c /bin/sh --'" ]) + +- self.expect ("help -a", ++ self.expect ("help", + substrs = [ 'run', 'process launch -c /bin/sh' ]) + +- self.expect ("help", matching=False, ++ self.expect ("help -a", matching=False, + substrs = [ "'run'", 'process launch -c /bin/sh' ]) + + self.expect ("run", Index: patches/lldb_fix_abbreviation_test.patch =================================================================== --- /dev/null +++ patches/lldb_fix_abbreviation_test.patch @@ -0,0 +1,13 @@ +Index: test/functionalities/abbreviation/TestAbbreviations.py +=================================================================== +--- test/functionalities/abbreviation/TestAbbreviations.py (revision 226488) ++++ test/functionalities/abbreviation/TestAbbreviations.py (working copy) +@@ -34,7 +34,7 @@ + + # Only one matching command: execute it. + self.expect("h", +- startstr = "The following is a list of built-in, permanent debugger commands:") ++ startstr = "Debugger commands:") + + # Execute cleanup function during test tear down + def cleanup(): Index: patches/lldb_fix_build_after_r223433.patch =================================================================== --- /dev/null +++ patches/lldb_fix_build_after_r223433.patch @@ -0,0 +1,13 @@ +Index: source/Expression/ClangModulesDeclVendor.cpp +=================================================================== +--- source/Expression/ClangModulesDeclVendor.cpp (revision 223474) ++++ source/Expression/ClangModulesDeclVendor.cpp (working copy) +@@ -7,7 +7,7 @@ + // + //===----------------------------------------------------------------------===// + +-#include "ClangModulesDeclVendor.h" ++#include "lldb/Expression/ClangModulesDeclVendor.h" + + #include "lldb/Core/StreamString.h" + #include "lldb/Host/FileSpec.h" Index: patches/lldb_fix_darwin_debug_build.patch =================================================================== --- /dev/null +++ patches/lldb_fix_darwin_debug_build.patch @@ -0,0 +1,131 @@ +Index: scripts/Python/finish-swig-Python-LLDB.sh +=================================================================== +--- scripts/Python/finish-swig-Python-LLDB.sh (revision 226677) ++++ scripts/Python/finish-swig-Python-LLDB.sh (working copy) +@@ -167,6 +167,22 @@ + fi + fi + ++if [ ! -L "${framework_python_dir}/darwin-debug" ] ++then ++ if [ $Debug -eq 1 ] ++ then ++ echo "Creating symlink for darwin-debug" ++ fi ++ cd "${framework_python_dir}" ++ if [ $MakefileCalled -ne 0 ] ++ ln -s "../../../../bin/lldb-launcher" darwin-debug ++ fi ++else ++ if [ $Debug -eq 1 ] ++ then ++ echo "${framework_python_dir}/darwin-debug already exists." ++ fi ++fi + + create_python_package () { + package_dir="${framework_python_dir}$1" +Index: scripts/Python/finishSwigPythonLLDB.py +=================================================================== +--- scripts/Python/finishSwigPythonLLDB.py (revision 226677) ++++ scripts/Python/finishSwigPythonLLDB.py (working copy) +@@ -330,6 +330,53 @@ + return (bOk, strMsg); + + #++--------------------------------------------------------------------------- ++# Details: Make the symbolic link to the darwin-debug. Code for all platforms ++# apart from Windows. ++# Args: vDictArgs - (R) Program input parameters. ++# vstrFrameworkPythonDir - (R) Python framework directory. ++# vstrDarwinDebugFileName - (R) File name for darwin-debug. ++# Returns: Bool - True = function success, False = failure. ++# Str - Error description on task failure. ++# Throws: None. ++#-- ++def make_symlink_darwin_debug( vDictArgs, vstrFrameworkPythonDir, vstrDarwinDebugFileName ): ++ dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); ++ bOk = True; ++ strMsg = ""; ++ bDbg = vDictArgs.has_key( "-d" ); ++ strTarget = vstrDarwinDebugFileName ++ strDarwinDebugPath = "%s/%s" % (vstrFrameworkPythonDir, strTarget); ++ strTarget = os.path.normcase( strDarwinDebugPath ); ++ strSrc = ""; ++ ++ os.chdir( vstrFrameworkPythonDir ); ++ bMakeFileCalled = vDictArgs.has_key( "-m" ); ++ if not bMakeFileCalled: ++ return (bOk, strMsg); ++ else: ++ strSrc = os.path.normcase( "../../../bin/lldb-launcher" ); ++ ++ if os.path.islink( strTarget ): ++ if bDbg: ++ print strMsglldbsoExists % strTarget; ++ return (bOk, strMsg); ++ ++ if bDbg: ++ print strMsglldbsoMk; ++ ++ try: ++ os.symlink( strSrc, strTarget ); ++ except OSError as e: ++ bOk = False; ++ strMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); ++ strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); ++ except: ++ bOk = False; ++ strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; ++ ++ return (bOk, strMsg); ++ ++#++--------------------------------------------------------------------------- + # Details: Make the symlink that the script bridge for Python will need in + # the Python framework directory. + # Args: vDictArgs - (R) Program input parameters. +@@ -343,9 +390,10 @@ + bOk = True; + strWkDir = ""; + strErrMsg = ""; ++ eOSType = utilsOsType.determine_os_type(); ++ ++ # Make symlink for _lldb + strSoFileName = "_lldb"; +- +- eOSType = utilsOsType.determine_os_type(); + if eOSType == utilsOsType.EnumOsType.Unknown: + bOk = False; + strErrMsg = strErrMsgOsTypeUnknown; +@@ -357,6 +405,14 @@ + bOk, strErrMsg = make_symlink_other_platforms( vDictArgs, + vstrFrameworkPythonDir, + strSoFileName ); ++ ++ # Make symlink for darwin-debug ++ strDarwinDebugFileName = "darwin-debug" ++ if bOk and eOSType == utilsOsType.EnumOsType.Darwin: ++ bOk, strErrMsg = make_symlink_darwin_debug( vDictArgs, ++ vstrFrameworkPythonDir, ++ strDarwinDebugFileName ); ++ + return (bOk, strErrMsg); + + #++--------------------------------------------------------------------------- +Index: tools/CMakeLists.txt +=================================================================== +--- tools/CMakeLists.txt (revision 226677) ++++ tools/CMakeLists.txt (working copy) +@@ -1,4 +1,5 @@ + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") ++ add_subdirectory(darwin-debug) + add_subdirectory(debugserver) + endif() + add_subdirectory(driver) +Index: tools/darwin-debug/CMakeLists.txt +=================================================================== +--- tools/darwin-debug/CMakeLists.txt (revision 0) ++++ tools/darwin-debug/CMakeLists.txt (working copy) +@@ -0,0 +1,3 @@ ++add_lldb_executable(lldb-launcher ++ darwin-debug.cpp ++ ) Index: patches/lldb_fix_darwin_debug_build.v2.patch =================================================================== --- /dev/null +++ patches/lldb_fix_darwin_debug_build.v2.patch @@ -0,0 +1,131 @@ +Index: scripts/Python/finish-swig-Python-LLDB.sh +=================================================================== +--- scripts/Python/finish-swig-Python-LLDB.sh (revision 226677) ++++ scripts/Python/finish-swig-Python-LLDB.sh (working copy) +@@ -167,6 +167,22 @@ + fi + fi + ++if [ ! -L "${framework_python_dir}/darwin-debug" ] ++then ++ if [ $Debug -eq 1 ] ++ then ++ echo "Creating symlink for darwin-debug" ++ fi ++ cd "${framework_python_dir}" ++ if [ $MakefileCalled -ne 0 ] ++ ln -s "../../../../bin/lldb-launcher" darwin-debug ++ fi ++else ++ if [ $Debug -eq 1 ] ++ then ++ echo "${framework_python_dir}/darwin-debug already exists." ++ fi ++fi + + create_python_package () { + package_dir="${framework_python_dir}$1" +Index: scripts/Python/finishSwigPythonLLDB.py +=================================================================== +--- scripts/Python/finishSwigPythonLLDB.py (revision 226677) ++++ scripts/Python/finishSwigPythonLLDB.py (working copy) +@@ -330,6 +330,53 @@ + return (bOk, strMsg); + + #++--------------------------------------------------------------------------- ++# Details: Make the symbolic link to the darwin-debug. Code for all platforms ++# apart from Windows. ++# Args: vDictArgs - (R) Program input parameters. ++# vstrFrameworkPythonDir - (R) Python framework directory. ++# vstrDarwinDebugFileName - (R) File name for darwin-debug. ++# Returns: Bool - True = function success, False = failure. ++# Str - Error description on task failure. ++# Throws: None. ++#-- ++def make_symlink_darwin_debug( vDictArgs, vstrFrameworkPythonDir, vstrDarwinDebugFileName ): ++ dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); ++ bOk = True; ++ strMsg = ""; ++ bDbg = vDictArgs.has_key( "-d" ); ++ strTarget = vstrDarwinDebugFileName ++ strDarwinDebugPath = "%s/%s" % (vstrFrameworkPythonDir, strTarget); ++ strTarget = os.path.normcase( strDarwinDebugPath ); ++ strSrc = ""; ++ ++ os.chdir( vstrFrameworkPythonDir ); ++ bMakeFileCalled = vDictArgs.has_key( "-m" ); ++ if not bMakeFileCalled: ++ return (bOk, strMsg); ++ else: ++ strSrc = os.path.normcase( "../../../../bin/lldb-launcher" ); ++ ++ if os.path.islink( strTarget ): ++ if bDbg: ++ print strMsglldbsoExists % strTarget; ++ return (bOk, strMsg); ++ ++ if bDbg: ++ print strMsglldbsoMk; ++ ++ try: ++ os.symlink( strSrc, strTarget ); ++ except OSError as e: ++ bOk = False; ++ strMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); ++ strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); ++ except: ++ bOk = False; ++ strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; ++ ++ return (bOk, strMsg); ++ ++#++--------------------------------------------------------------------------- + # Details: Make the symlink that the script bridge for Python will need in + # the Python framework directory. + # Args: vDictArgs - (R) Program input parameters. +@@ -343,9 +390,10 @@ + bOk = True; + strWkDir = ""; + strErrMsg = ""; ++ eOSType = utilsOsType.determine_os_type(); ++ ++ # Make symlink for _lldb + strSoFileName = "_lldb"; +- +- eOSType = utilsOsType.determine_os_type(); + if eOSType == utilsOsType.EnumOsType.Unknown: + bOk = False; + strErrMsg = strErrMsgOsTypeUnknown; +@@ -357,6 +405,14 @@ + bOk, strErrMsg = make_symlink_other_platforms( vDictArgs, + vstrFrameworkPythonDir, + strSoFileName ); ++ ++ # Make symlink for darwin-debug ++ strDarwinDebugFileName = "darwin-debug" ++ if bOk and eOSType == utilsOsType.EnumOsType.Darwin: ++ bOk, strErrMsg = make_symlink_darwin_debug( vDictArgs, ++ vstrFrameworkPythonDir, ++ strDarwinDebugFileName ); ++ + return (bOk, strErrMsg); + + #++--------------------------------------------------------------------------- +Index: tools/CMakeLists.txt +=================================================================== +--- tools/CMakeLists.txt (revision 226677) ++++ tools/CMakeLists.txt (working copy) +@@ -1,4 +1,5 @@ + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") ++ add_subdirectory(darwin-debug) + add_subdirectory(debugserver) + endif() + add_subdirectory(driver) +Index: tools/darwin-debug/CMakeLists.txt +=================================================================== +--- tools/darwin-debug/CMakeLists.txt (revision 0) ++++ tools/darwin-debug/CMakeLists.txt (working copy) +@@ -0,0 +1,3 @@ ++add_lldb_executable(lldb-launcher ++ darwin-debug.cpp ++ ) Index: patches/lldb_fix_darwin_debug_build.v3.patch =================================================================== --- /dev/null +++ patches/lldb_fix_darwin_debug_build.v3.patch @@ -0,0 +1,135 @@ +Index: scripts/Python/finish-swig-Python-LLDB.sh +=================================================================== +--- scripts/Python/finish-swig-Python-LLDB.sh (revision 226677) ++++ scripts/Python/finish-swig-Python-LLDB.sh (working copy) +@@ -167,7 +167,26 @@ + fi + fi + ++if [ ${OS_NAME} = "Darwin" ] && [ $MakefileCalled -ne 0 ] ++then ++ # We are being built by CMake on Darwin + ++ if [ ! -L "${framework_python_dir}/darwin-debug" ] ++ then ++ if [ $Debug -eq 1 ] ++ then ++ echo "Creating symlink for darwin-debug" ++ fi ++ cd "${framework_python_dir}" ++ ln -s "../../../../bin/lldb-launcher" darwin-debug ++ else ++ if [ $Debug -eq 1 ] ++ then ++ echo "${framework_python_dir}/darwin-debug already exists." ++ fi ++ fi ++fi ++ + create_python_package () { + package_dir="${framework_python_dir}$1" + package_files="$2" +Index: scripts/Python/finishSwigPythonLLDB.py +=================================================================== +--- scripts/Python/finishSwigPythonLLDB.py (revision 226677) ++++ scripts/Python/finishSwigPythonLLDB.py (working copy) +@@ -330,6 +330,53 @@ + return (bOk, strMsg); + + #++--------------------------------------------------------------------------- ++# Details: Make the symbolic link to the darwin-debug. Code for all platforms ++# apart from Windows. ++# Args: vDictArgs - (R) Program input parameters. ++# vstrFrameworkPythonDir - (R) Python framework directory. ++# vstrDarwinDebugFileName - (R) File name for darwin-debug. ++# Returns: Bool - True = function success, False = failure. ++# Str - Error description on task failure. ++# Throws: None. ++#-- ++def make_symlink_darwin_debug( vDictArgs, vstrFrameworkPythonDir, vstrDarwinDebugFileName ): ++ dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); ++ bOk = True; ++ strMsg = ""; ++ bDbg = vDictArgs.has_key( "-d" ); ++ strTarget = vstrDarwinDebugFileName ++ strDarwinDebugPath = "%s/%s" % (vstrFrameworkPythonDir, strTarget); ++ strTarget = os.path.normcase( strDarwinDebugPath ); ++ strSrc = ""; ++ ++ os.chdir( vstrFrameworkPythonDir ); ++ bMakeFileCalled = vDictArgs.has_key( "-m" ); ++ if not bMakeFileCalled: ++ return (bOk, strMsg); ++ else: ++ strSrc = os.path.normcase( "../../../../bin/lldb-launcher" ); ++ ++ if os.path.islink( strTarget ): ++ if bDbg: ++ print strMsglldbsoExists % strTarget; ++ return (bOk, strMsg); ++ ++ if bDbg: ++ print strMsglldbsoMk; ++ ++ try: ++ os.symlink( strSrc, strTarget ); ++ except OSError as e: ++ bOk = False; ++ strMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); ++ strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); ++ except: ++ bOk = False; ++ strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; ++ ++ return (bOk, strMsg); ++ ++#++--------------------------------------------------------------------------- + # Details: Make the symlink that the script bridge for Python will need in + # the Python framework directory. + # Args: vDictArgs - (R) Program input parameters. +@@ -343,9 +390,10 @@ + bOk = True; + strWkDir = ""; + strErrMsg = ""; ++ eOSType = utilsOsType.determine_os_type(); ++ ++ # Make symlink for _lldb + strSoFileName = "_lldb"; +- +- eOSType = utilsOsType.determine_os_type(); + if eOSType == utilsOsType.EnumOsType.Unknown: + bOk = False; + strErrMsg = strErrMsgOsTypeUnknown; +@@ -357,6 +405,14 @@ + bOk, strErrMsg = make_symlink_other_platforms( vDictArgs, + vstrFrameworkPythonDir, + strSoFileName ); ++ ++ # Make symlink for darwin-debug ++ strDarwinDebugFileName = "darwin-debug" ++ if bOk and eOSType == utilsOsType.EnumOsType.Darwin: ++ bOk, strErrMsg = make_symlink_darwin_debug( vDictArgs, ++ vstrFrameworkPythonDir, ++ strDarwinDebugFileName ); ++ + return (bOk, strErrMsg); + + #++--------------------------------------------------------------------------- +Index: tools/CMakeLists.txt +=================================================================== +--- tools/CMakeLists.txt (revision 226677) ++++ tools/CMakeLists.txt (working copy) +@@ -1,4 +1,5 @@ + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") ++ add_subdirectory(darwin-debug) + add_subdirectory(debugserver) + endif() + add_subdirectory(driver) +Index: tools/darwin-debug/CMakeLists.txt +=================================================================== +--- tools/darwin-debug/CMakeLists.txt (revision 0) ++++ tools/darwin-debug/CMakeLists.txt (working copy) +@@ -0,0 +1,3 @@ ++add_lldb_executable(lldb-launcher ++ darwin-debug.cpp ++ ) Index: patches/lldb_fix_target_launch_stop_at_entry_arg.patch =================================================================== --- /dev/null +++ patches/lldb_fix_target_launch_stop_at_entry_arg.patch @@ -0,0 +1,14 @@ +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 227493) ++++ source/API/SBTarget.cpp (working copy) +@@ -729,6 +729,9 @@ + { + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + ++ if (stop_at_entry) ++ launch_flags |= eLaunchFlagStopAtEntry; ++ + if (getenv("LLDB_LAUNCH_FLAG_DISABLE_ASLR")) + launch_flags |= eLaunchFlagDisableASLR; + Index: patches/lldb_mi_added_test_for_exit.patch =================================================================== --- /dev/null +++ patches/lldb_mi_added_test_for_exit.patch @@ -0,0 +1,132 @@ +Index: tools/lldb-mi/TestMiExit.py +=================================================================== +--- tools/lldb-mi/TestMiExit.py (revision 0) ++++ tools/lldb-mi/TestMiExit.py (working copy) +@@ -0,0 +1,127 @@ ++""" ++Test that the lldb-mi driver works properly with "-gdb-exit". ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiExitTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_gdbexit(self): ++ """Test that '-gdb-exit' terminates debug session and exits.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # load executable ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.sendline("") #FIXME: hangs here; extra return below is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # send -gdb-exit and check that program is finished ++ child.sendline("-gdb-exit") ++ child.expect("\^exit") ++ child.sendline("") #FIXME: hangs here; extra return below is needed ++ child.expect("MI: Program exited OK") ++ child.expect(pexpect.EOF) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_quit(self): ++ """Test that 'quit' exits immediately.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # load executable ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.sendline("") #FIXME: hangs here; extra return below is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # send quit and check that program is finished ++ child.sendline("quit") ++ child.expect("MI: Program exited OK") ++ child.expect(pexpect.EOF) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() Index: patches/lldbmi_CLI_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_CLI_support.v2.patch @@ -0,0 +1,432 @@ +Index: include/lldb/API/SBDebugger.h +=================================================================== +--- include/lldb/API/SBDebugger.h (revision 222919) ++++ include/lldb/API/SBDebugger.h (working copy) +@@ -15,6 +15,8 @@ + #include "lldb/API/SBDefines.h" + #include "lldb/API/SBPlatform.h" + ++class CMICmnLLDBDebugSessionInfo; ++ + namespace lldb { + + +@@ -337,6 +339,7 @@ + friend class SBProcess; + friend class SBSourceManager; + friend class SBTarget; ++ friend class ::CMICmnLLDBDebugSessionInfo; // for UpdateLLDBDebugSessionInfo + + lldb::SBTarget + FindTargetWithLLDBProcess (const lldb::ProcessSP &processSP); +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 222919) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -20,6 +20,8 @@ + #include "lldb/API/SBValue.h" + #include "lldb/API/SBWatchpoint.h" + ++class CMICmnLLDBDebugSessionInfo; ++ + namespace lldb { + + class SBPlatform; +@@ -1055,6 +1057,7 @@ + friend class SBSourceManager; + friend class SBSymbol; + friend class SBValue; ++ friend class ::CMICmnLLDBDebugSessionInfo; // for UpdateLLDBDebugSessionInfo + + //------------------------------------------------------------------ + // Constructors are private, use static Target::Create function to +Index: test/tools/lldb-mi/TestMiCliSupport.py +=================================================================== +--- test/tools/lldb-mi/TestMiCliSupport.py (revision 0) ++++ test/tools/lldb-mi/TestMiCliSupport.py (working copy) +@@ -0,0 +1,221 @@ ++""" ++Test that the lldb-mi driver handles CLI commands correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiCliSupportTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_targetcreate(self): ++ """Test that 'lldb-mi --interpreter' can create target by 'target create' command.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("target create %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_breakpoint(self): ++ """Test that 'lldb-mi --interpreter' can execute breakpoint commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("b main") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("'setting set target.run-args' doesn't work yet") ++ @lldbmi_test ++ def test_lldbmi_settargetargs(self): ++ """Test that 'lldb-mi --interpreter' can execute 'setting set target.run-args' correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("setting set target.run-args 1") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert --file main.c:21") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("~\"argc=2") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execution(self): ++ """Test that 'lldb-mi --interpreter' can execute 'run', 'next', 'step' and 'continue' commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Setup breakpoints ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-break-insert --file main.c:30") ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # Test them ++ child.sendline("r") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^done") ++ child.expect("Target ") #FIXME: sync before 'next' command ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("~\"argc=1") ++ child.sendline("s") ++ child.expect("\^done") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("\~\"a is about to return 10.") ++ child.sendline("c") ++ child.expect("\^done") ++ child.expect("~\"b is about to return 20.") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 222919) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -473,6 +473,9 @@ + rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + ++ // Update CMICmnLLDBDebugSessionInfo ++ rSessionInfo.UpdateLLDBDebugSessionInfo(); ++ + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 222919) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -39,6 +39,8 @@ + #include "MICmdData.h" + #include "MICmnLLDBUtilSBValue.h" + ++#include "lldb/Core/Debugger.h" ++ + //++ ------------------------------------------------------------------------------------ + // Details: CMICmnLLDBDebugSessionInfo constructor. + // Type: Method. +@@ -1365,3 +1367,22 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Update LLDBDebugSessionInfo. It uses m_rLldbDebugger to obtain ++// the latest information. For example, get current target ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++void ++CMICmnLLDBDebugSessionInfo::UpdateLLDBDebugSessionInfo(void) ++{ ++ lldb::DebuggerSP debuggerSP = m_rLldbDebugger.get_sp(); ++ lldb::TargetSP targetSP = debuggerSP->GetSelectedTarget(); ++ if (m_lldbTarget.GetSP() != targetSP) ++ { ++ m_lldbTarget = lldb::SBTarget(targetSP); ++ } ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 222919) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -143,6 +143,7 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ void UpdateLLDBDebugSessionInfo(void); + + // Attributes: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 222919) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -977,6 +977,25 @@ + return bOk; + } + ++// Helper function for CMIDriver::InterpretCommandThisDriver. ++// Turn the string into something that can be embedded in a string. ++static std::string ++stringify(const std::string &s) ++{ ++ std::string result; ++ result.reserve(s.length() + 2); ++ result += '"'; ++ const std::string::const_iterator last = s.end(); ++ for (std::string::const_iterator p = s.begin(); p != last; ++p) ++ { ++ if (*p == '"' || *p == '\\') ++ result += '\\'; ++ result += *p; ++ } ++ result += '"'; ++ return result; ++} ++ + //++ ------------------------------------------------------------------------------------ + // Details: Interpret the text data and match against current commands to see if there + // is a match. If a match then the command is issued and actioned on. If a +@@ -985,7 +1004,7 @@ + // This function is used by the application's main thread. + // Type: Method. + // Args: vTextLine - (R) Text data representing a possible command. +-// vwbCmdYesValid - (W) True = Command invalid, false = command acted on. ++// vwbCmdYesValid - (W) True = Command valid, false = command not handled. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. +@@ -993,12 +1012,19 @@ + bool + CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid) + { ++ // Make sure we have a valid MI command ++ CMIUtilString vMITextLine(vTextLine); ++ if (vTextLine.at(0) != '-') ++ { ++ // Wrap non-MI commands to make them MI-compatible. ++ vMITextLine = "-interpreter-exec command " + stringify(vTextLine); ++ } ++ + vwbCmdYesValid = false; +- + bool bCmdNotInCmdFactor = false; + SMICmdData cmdData; + CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); +- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) ++ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) + return MIstatus::failure; + + if (vwbCmdYesValid) +@@ -1012,12 +1038,12 @@ + // Check for escape character, may be cursor control characters + // This code is not necessary for application operation, just want to keep tabs on what + // is been given to the driver to try and intepret. +- if (vTextLine.at(0) == 27) ++ if (vMITextLine.at(0) == 27) + { + CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); +- for (MIuint i = 0; i < vTextLine.length(); i++) ++ for (MIuint i = 0; i < vMITextLine.length(); i++) + { +- logInput += CMIUtilString::Format("%d ", vTextLine.at(i)); ++ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); + } + m_pLog->WriteLog(logInput); + return MIstatus::success; +@@ -1030,7 +1056,7 @@ + strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); + const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); + const CMIUtilString msg( +- CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); ++ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); + const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 222919) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -175,8 +175,8 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) + }; Index: patches/lldbmi_CLI_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_CLI_support.v3.patch @@ -0,0 +1,449 @@ +Index: include/lldb/API/SBDebugger.h +=================================================================== +--- include/lldb/API/SBDebugger.h (revision 222919) ++++ include/lldb/API/SBDebugger.h (working copy) +@@ -15,6 +15,8 @@ + #include "lldb/API/SBDefines.h" + #include "lldb/API/SBPlatform.h" + ++class CMICmnLLDBDebugSessionInfo; ++ + namespace lldb { + + +@@ -337,6 +339,7 @@ + friend class SBProcess; + friend class SBSourceManager; + friend class SBTarget; ++ friend class ::CMICmnLLDBDebugSessionInfo; // for UpdateLLDBDebugSessionInfo + + lldb::SBTarget + FindTargetWithLLDBProcess (const lldb::ProcessSP &processSP); +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 222919) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -20,6 +20,8 @@ + #include "lldb/API/SBValue.h" + #include "lldb/API/SBWatchpoint.h" + ++class CMICmnLLDBDebugSessionInfo; ++ + namespace lldb { + + class SBPlatform; +@@ -1055,6 +1057,7 @@ + friend class SBSourceManager; + friend class SBSymbol; + friend class SBValue; ++ friend class ::CMICmnLLDBDebugSessionInfo; // for UpdateLLDBDebugSessionInfo + + //------------------------------------------------------------------ + // Constructors are private, use static Target::Create function to +Index: test/tools/lldb-mi/TestMiCliSupport.py +=================================================================== +--- test/tools/lldb-mi/TestMiCliSupport.py (revision 0) ++++ test/tools/lldb-mi/TestMiCliSupport.py (working copy) +@@ -0,0 +1,221 @@ ++""" ++Test that the lldb-mi driver handles CLI commands correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiCliSupportTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_targetcreate(self): ++ """Test that 'lldb-mi --interpreter' can create target by 'target create' command.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("target create %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_breakpoint(self): ++ """Test that 'lldb-mi --interpreter' can execute breakpoint commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("b main") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("'setting set target.run-args' doesn't work yet") ++ @lldbmi_test ++ def test_lldbmi_settargetargs(self): ++ """Test that 'lldb-mi --interpreter' can execute 'setting set target.run-args' correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("setting set target.run-args 1") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert --file main.c:21") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("~\"argc=2") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execution(self): ++ """Test that 'lldb-mi --interpreter' can execute 'run', 'next', 'step' and 'continue' commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Setup breakpoints ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-break-insert --file main.c:30") ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # Test them ++ child.sendline("r") ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed ++ child.expect("\^done") ++ child.expect("Target ") #FIXME: sync before 'next' command ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("~\"argc=1") ++ child.sendline("s") ++ child.expect("\^done") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("\~\"a is about to return 10.") ++ child.sendline("c") ++ child.expect("\^done") ++ child.expect("~\"b is about to return 20.") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 222919) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -473,6 +473,9 @@ + rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + ++ // Update CMICmnLLDBDebugSessionInfo ++ rSessionInfo.UpdateLLDBDebugSessionInfo(); ++ + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 222919) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -39,6 +39,8 @@ + #include "MICmdData.h" + #include "MICmnLLDBUtilSBValue.h" + ++#include "lldb/Core/Debugger.h" ++ + //++ ------------------------------------------------------------------------------------ + // Details: CMICmnLLDBDebugSessionInfo constructor. + // Type: Method. +@@ -1365,3 +1367,22 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Update LLDBDebugSessionInfo. It uses m_rLldbDebugger to obtain ++// the latest information. For example, get current target ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++void ++CMICmnLLDBDebugSessionInfo::UpdateLLDBDebugSessionInfo(void) ++{ ++ lldb::DebuggerSP debuggerSP = m_rLldbDebugger.get_sp(); ++ lldb::TargetSP targetSP = debuggerSP->GetSelectedTarget(); ++ if (m_lldbTarget.GetSP() != targetSP) ++ { ++ m_lldbTarget = lldb::SBTarget(targetSP); ++ } ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 222919) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -143,6 +143,7 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ void UpdateLLDBDebugSessionInfo(void); + + // Attributes: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 222919) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -977,6 +977,47 @@ + return bOk; + } + ++// Helper function for WrapCliCommandIntoMiCommand. ++// Turn the string into something that can be embedded in a string. ++static std::string ++stringify(const std::string &s) ++{ ++ std::string result; ++ result.reserve(s.length() + 2); ++ result += '"'; ++ const std::string::const_iterator last = s.end(); ++ for (std::string::const_iterator p = s.begin(); p != last; ++p) ++ { ++ if (*p == '"' || *p == '\\') ++ result += '\\'; ++ result += *p; ++ } ++ result += '"'; ++ return result; ++} ++ ++// Helper function for CMIDriver::InterpretCommandThisDriver. ++// Convert CLI commands into MI commands using '-interpreter-exec command'. ++static CMIUtilString ++WrapCliCommandIntoMiCommand(const CMIUtilString &vTextLine) ++{ ++ static const std::string digits("0123456789"); ++ const size_t nCommandOffset = vTextLine.find_first_not_of(digits); ++ const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos); ++ const bool bIsCliCommand = !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-'); ++ if (!bIsCliCommand) ++ { ++ return vTextLine; ++ } ++ ++ // Wrap CLI command to make it MI-compatible ++ const std::string vToken(vTextLine.begin(), vTextLine.begin() + nCommandOffset); ++ const std::string vCliCommand(vTextLine, nCommandOffset); ++ const std::string vShieldedCliCommand(stringify(vCliCommand)); ++ return CMIUtilString::Format("%s-interpreter-exec command %s", ++ vToken.c_str(), vShieldedCliCommand.c_str()); ++} ++ + //++ ------------------------------------------------------------------------------------ + // Details: Interpret the text data and match against current commands to see if there + // is a match. If a match then the command is issued and actioned on. If a +@@ -985,7 +1026,7 @@ + // This function is used by the application's main thread. + // Type: Method. + // Args: vTextLine - (R) Text data representing a possible command. +-// vwbCmdYesValid - (W) True = Command invalid, false = command acted on. ++// vwbCmdYesValid - (W) True = Command valid, false = command not handled. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. +@@ -993,12 +1034,14 @@ + bool + CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid) + { ++ // Make sure we have a valid MI command ++ CMIUtilString vMITextLine(WrapCliCommandIntoMiCommand(vTextLine)); ++ + vwbCmdYesValid = false; +- + bool bCmdNotInCmdFactor = false; + SMICmdData cmdData; + CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); +- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) ++ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) + return MIstatus::failure; + + if (vwbCmdYesValid) +@@ -1012,12 +1055,12 @@ + // Check for escape character, may be cursor control characters + // This code is not necessary for application operation, just want to keep tabs on what + // is been given to the driver to try and intepret. +- if (vTextLine.at(0) == 27) ++ if (vMITextLine.at(0) == 27) + { + CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); +- for (MIuint i = 0; i < vTextLine.length(); i++) ++ for (MIuint i = 0; i < vMITextLine.length(); i++) + { +- logInput += CMIUtilString::Format("%d ", vTextLine.at(i)); ++ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); + } + m_pLog->WriteLog(logInput); + return MIstatus::success; +@@ -1030,7 +1073,7 @@ + strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); + const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); + const CMIUtilString msg( +- CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); ++ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); + const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 222919) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -175,8 +175,8 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) + }; Index: patches/lldbmi_CLI_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_CLI_support.v4.patch @@ -0,0 +1,335 @@ +Index: test/tools/lldb-mi/TestMiCliSupport.py +=================================================================== +--- test/tools/lldb-mi/TestMiCliSupport.py (revision 0) ++++ test/tools/lldb-mi/TestMiCliSupport.py (working copy) +@@ -0,0 +1,229 @@ ++""" ++Test that the lldb-mi driver handles CLI commands correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiCliSupportTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_targetcreate(self): ++ """Test that 'lldb-mi --interpreter' can create target by 'target create' command.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("target create %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_breakpoint(self): ++ """Test that 'lldb-mi --interpreter' can execute breakpoint commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("b main") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("'setting set target.run-args' doesn't work yet") ++ @lldbmi_test ++ def test_lldbmi_settargetargs(self): ++ """Test that 'lldb-mi --interpreter' can execute 'setting set target.run-args' correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("setting set target.run-args 1") ++ child.expect("\^done") ++ ++ # Run to main ++ self.line = line_number('main.c', '//BP_argctest') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("~\"argc=2") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_execution(self): ++ """Test that 'lldb-mi --interpreter' can execute 'run', 'next', 'step' and 'continue' commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("-exec-arguments 1") ++ child.expect("\^done") ++ ++ # Setup breakpoints ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ self.line = line_number('main.c', '//BP_source') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # Test them ++ child.sendline("r") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("~\"argc=2") ++ child.sendline("s") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("\~\"a is about to return 10.") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("c") ++ child.expect("\^done") ++ child.expect("~\"b is about to return 20.") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224992) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -977,6 +977,45 @@ + return bOk; + } + ++// Helper function for WrapCliCommandIntoMiCommand. ++// Turn the string into something that can be embedded in a string. ++static std::string ++stringify(const std::string &s) ++{ ++ std::string result; ++ result.reserve(s.length() + 2); ++ result += '"'; ++ const std::string::const_iterator last = s.end(); ++ for (std::string::const_iterator p = s.begin(); p != last; ++p) ++ { ++ if (*p == '"' || *p == '\\') ++ result += '\\'; ++ result += *p; ++ } ++ result += '"'; ++ return result; ++} ++ ++// Helper function for CMIDriver::InterpretCommandThisDriver. ++// Convert CLI commands into MI commands using '-interpreter-exec command'. ++static CMIUtilString ++WrapCliCommandIntoMiCommand(const CMIUtilString &vTextLine) ++{ ++ static const std::string digits("0123456789"); ++ const size_t nCommandOffset = vTextLine.find_first_not_of(digits); ++ const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos); ++ const bool bIsCliCommand = !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-'); ++ if (!bIsCliCommand) ++ return vTextLine; ++ ++ // Wrap CLI command to make it MI-compatible ++ const std::string vToken(vTextLine.begin(), vTextLine.begin() + nCommandOffset); ++ const std::string vCliCommand(vTextLine, nCommandOffset); ++ const std::string vShieldedCliCommand(stringify(vCliCommand)); ++ return CMIUtilString::Format("%s-interpreter-exec command %s", ++ vToken.c_str(), vShieldedCliCommand.c_str()); ++} ++ + //++ ------------------------------------------------------------------------------------ + // Details: Interpret the text data and match against current commands to see if there + // is a match. If a match then the command is issued and actioned on. If a +@@ -985,7 +1024,7 @@ + // This function is used by the application's main thread. + // Type: Method. + // Args: vTextLine - (R) Text data representing a possible command. +-// vwbCmdYesValid - (W) True = Command invalid, false = command acted on. ++// vwbCmdYesValid - (W) True = Command valid, false = command not handled. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. +@@ -993,12 +1032,14 @@ + bool + CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid) + { ++ // Make sure we have a valid MI command ++ CMIUtilString vMITextLine(WrapCliCommandIntoMiCommand(vTextLine)); ++ + vwbCmdYesValid = false; +- + bool bCmdNotInCmdFactor = false; + SMICmdData cmdData; + CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); +- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) ++ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) + return MIstatus::failure; + + if (vwbCmdYesValid) +@@ -1012,12 +1053,12 @@ + // Check for escape character, may be cursor control characters + // This code is not necessary for application operation, just want to keep tabs on what + // is been given to the driver to try and intepret. +- if (vTextLine.at(0) == 27) ++ if (vMITextLine.at(0) == 27) + { + CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); +- for (MIuint i = 0; i < vTextLine.length(); i++) ++ for (MIuint i = 0; i < vMITextLine.length(); i++) + { +- logInput += CMIUtilString::Format("%d ", vTextLine.at(i)); ++ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); + } + m_pLog->WriteLog(logInput); + return MIstatus::success; +@@ -1030,7 +1071,7 @@ + strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); + const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); + const CMIUtilString msg( +- CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); ++ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); + const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); Index: patches/lldbmi_CLI_support.v5.patch =================================================================== --- /dev/null +++ patches/lldbmi_CLI_support.v5.patch @@ -0,0 +1,335 @@ +Index: test/tools/lldb-mi/TestMiCliSupport.py +=================================================================== +--- test/tools/lldb-mi/TestMiCliSupport.py (revision 0) ++++ test/tools/lldb-mi/TestMiCliSupport.py (working copy) +@@ -0,0 +1,229 @@ ++""" ++Test that the lldb-mi driver handles CLI commands correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiCliSupportTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_targetcreate(self): ++ """Test that 'lldb-mi --interpreter' can create target by 'target create' command.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("target create %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_breakpoint(self): ++ """Test that 'lldb-mi --interpreter' can execute breakpoint commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("b main") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("'setting set target.run-args' doesn't work yet") ++ @lldbmi_test ++ def test_lldbmi_settargetargs(self): ++ """Test that 'lldb-mi --interpreter' can execute 'setting set target.run-args' correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("setting set target.run-args 1") ++ child.expect("\^done") ++ ++ # Run to main ++ self.line = line_number('main.c', '//BP_argctest') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("~\"argc=2") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_execution(self): ++ """Test that 'lldb-mi --interpreter' can execute 'run', 'next', 'step' and 'continue' commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("-exec-arguments 1") ++ child.expect("\^done") ++ ++ # Setup breakpoints ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ self.line = line_number('main.c', '//BP_source') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # Test them ++ child.sendline("r") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("~\"argc=2") ++ child.sendline("s") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("\~\"a is about to return 10.") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("c") ++ child.expect("\^done") ++ child.expect("~\"b is about to return 20.") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224992) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -977,6 +977,45 @@ + return bOk; + } + ++// Helper function for WrapCliCommandIntoMiCommand. ++// Turn the string into something that can be embedded in a string. ++static std::string ++stringify(const std::string &s) ++{ ++ std::string result; ++ result.reserve(s.length() + 2); ++ result += '"'; ++ const std::string::const_iterator last = s.end(); ++ for (std::string::const_iterator p = s.begin(); p != last; ++p) ++ { ++ if (*p == '"' || *p == '\\') ++ result += '\\'; ++ result += *p; ++ } ++ result += '"'; ++ return result; ++} ++ ++// Helper function for CMIDriver::InterpretCommandThisDriver. ++// Convert CLI commands into MI commands using '-interpreter-exec command'. ++static CMIUtilString ++WrapCliCommandIntoMiCommand(const CMIUtilString &vTextLine) ++{ ++ static const CMIUtilString digits("0123456789"); ++ const MIuint nCommandOffset = vTextLine.find_first_not_of(digits); ++ const bool bIsEmptyCommand = (nCommandOffset == (MIuint)CMIUtilString::npos); ++ const bool bIsCliCommand = !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-'); ++ if (!bIsCliCommand) ++ return vTextLine; ++ ++ // Wrap CLI command to make it MI-compatible ++ const std::string vToken(vTextLine.begin(), vTextLine.begin() + nCommandOffset); ++ const std::string vCliCommand(vTextLine, nCommandOffset); ++ const std::string vShieldedCliCommand(stringify(vCliCommand)); ++ return CMIUtilString::Format("%s-interpreter-exec command %s", ++ vToken.c_str(), vShieldedCliCommand.c_str()); ++} ++ + //++ ------------------------------------------------------------------------------------ + // Details: Interpret the text data and match against current commands to see if there + // is a match. If a match then the command is issued and actioned on. If a +@@ -985,7 +1024,7 @@ + // This function is used by the application's main thread. + // Type: Method. + // Args: vTextLine - (R) Text data representing a possible command. +-// vwbCmdYesValid - (W) True = Command invalid, false = command acted on. ++// vwbCmdYesValid - (W) True = Command valid, false = command not handled. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. +@@ -993,12 +1032,14 @@ + bool + CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid) + { ++ // Make sure we have a valid MI command ++ CMIUtilString vMITextLine(WrapCliCommandIntoMiCommand(vTextLine)); ++ + vwbCmdYesValid = false; +- + bool bCmdNotInCmdFactor = false; + SMICmdData cmdData; + CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); +- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) ++ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) + return MIstatus::failure; + + if (vwbCmdYesValid) +@@ -1012,12 +1053,12 @@ + // Check for escape character, may be cursor control characters + // This code is not necessary for application operation, just want to keep tabs on what + // is been given to the driver to try and intepret. +- if (vTextLine.at(0) == 27) ++ if (vMITextLine.at(0) == 27) + { + CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); +- for (MIuint i = 0; i < vTextLine.length(); i++) ++ for (MIuint i = 0; i < vMITextLine.length(); i++) + { +- logInput += CMIUtilString::Format("%d ", vTextLine.at(i)); ++ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); + } + m_pLog->WriteLog(logInput); + return MIstatus::success; +@@ -1030,7 +1071,7 @@ + strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); + const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); + const CMIUtilString msg( +- CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); ++ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); + const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); Index: patches/lldbmi_CLI_support.v6.patch =================================================================== --- /dev/null +++ patches/lldbmi_CLI_support.v6.patch @@ -0,0 +1,382 @@ +Index: test/tools/lldb-mi/TestMiCliSupport.py +=================================================================== +--- test/tools/lldb-mi/TestMiCliSupport.py (revision 0) ++++ test/tools/lldb-mi/TestMiCliSupport.py (working copy) +@@ -0,0 +1,229 @@ ++""" ++Test that the lldb-mi driver handles CLI commands correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiCliSupportTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_targetcreate(self): ++ """Test that 'lldb-mi --interpreter' can create target by 'target create' command.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("target create %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_breakpoint(self): ++ """Test that 'lldb-mi --interpreter' can execute breakpoint commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("b main") ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("'setting set target.run-args' doesn't work yet") ++ @lldbmi_test ++ def test_lldbmi_settargetargs(self): ++ """Test that 'lldb-mi --interpreter' can execute 'setting set target.run-args' correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("setting set target.run-args 1") ++ child.expect("\^done") ++ ++ # Run to main ++ self.line = line_number('main.c', '//BP_argctest') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("~\"argc=2") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'session info' patch") ++ @lldbmi_test ++ def test_lldbmi_execution(self): ++ """Test that 'lldb-mi --interpreter' can execute 'run', 'next', 'step' and 'continue' commands correctly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Pass argument ++ child.sendline("-exec-arguments 1") ++ child.expect("\^done") ++ ++ # Setup breakpoints ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ self.line = line_number('main.c', '//BP_source') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # Test them ++ child.sendline("r") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("~\"argc=2") ++ child.sendline("s") ++ child.expect("\^done") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("n") ++ child.expect("\^done") ++ child.expect("\~\"a is about to return 10.") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ child.sendline("c") ++ child.expect("\^done") ++ child.expect("~\"b is about to return 20.") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 225039) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -977,6 +977,92 @@ + return bOk; + } + ++// Helper function for WrapCliCommandIntoMiCommand. ++// Turn the string into something that can be embedded in a string. ++static std::string ++stringify(const std::string &s) ++{ ++ std::string result; ++ result.reserve(s.length() + 2); ++ result += '"'; ++ const std::string::const_iterator last = s.end(); ++ for (std::string::const_iterator p = s.begin(); p != last; ++p) ++ { ++ if (*p == '"' || *p == '\\') ++ result += '\\'; ++ result += *p; ++ } ++ result += '"'; ++ return result; ++} ++ ++// Helper function for CMIDriver::InterpretCommandThisDriver. ++// Convert CLI commands into MI commands using '-interpreter-exec command'. ++static CMIUtilString ++WrapCliCommandIntoMiCommand(const CMIUtilString &vTextLine) ++{ ++ // Tokens contain following digits: ++ static const CMIUtilString digits("0123456789"); ++ ++ // Consider algorithm on following example: ++ // 001-file-exec-and-symbols "/path/to/file" ++ // ++ // Try to find start of the command: ++ const MIuint nCommandOffset = vTextLine.find_first_not_of(digits); ++ // Result: ++ // 001-file-exec-and-symbols "/path/to/file" ++ // 001target create "/path/to/file" ++ // ^ -- command starts here (in both cases) ++ // Also possible case when command not found: ++ // 001 ++ // ^ -- i.e. only tokens are present (or empty string at all) ++ ++ // Check if command is empty: ++ const bool bIsEmptyCommand = (nCommandOffset == (MIuint)CMIUtilString::npos); ++ // Result: ++ // 001-file-exec-and-symbols "/path/to/file" ++ // 001target create "/path/to/file" ++ // ^ -- command not empty (in both cases) ++ // or: ++ // 001 ++ // ^ -- command wasn't found ++ ++ // Check if command it isn't CLI command: ++ const bool bIsCliCommand = !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-'); ++ // Result: ++ // 001-file-exec-and-symbols "/path/to/file" ++ // 001 ++ // ^ -- it isn't CLI command (in both cases) ++ // or: ++ // 001target create "/path/to/file" ++ // ^ -- it's CLI command ++ ++ // Exit if it isn't CLI command: ++ if (!bIsCliCommand) ++ return vTextLine; ++ ++ // Wrap CLI command to make it MI-compatible and exit: ++ ++ const std::string vToken(vTextLine.begin(), vTextLine.begin() + nCommandOffset); ++ // 001target create "/path/to/file" ++ // ^^^ -- token ++ ++ const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset).c_str()); ++ // 001target create "/path/to/file" ++ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command ++ ++ const std::string vShieldedCliCommand(stringify(vCliCommand)); ++ // Result: it looks like -- target create \"/path/to/file\". ++ ++ // Format to following string: ++ // 001-interpreter-exec command "target create \"/path/to/file\"" ++ // ^^^ -- token ++ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ -- wrapper ++ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded CLI command ++ return CMIUtilString::Format("%s-interpreter-exec command %s", ++ vToken.c_str(), vShieldedCliCommand.c_str()); ++} ++ + //++ ------------------------------------------------------------------------------------ + // Details: Interpret the text data and match against current commands to see if there + // is a match. If a match then the command is issued and actioned on. If a +@@ -985,7 +1071,7 @@ + // This function is used by the application's main thread. + // Type: Method. + // Args: vTextLine - (R) Text data representing a possible command. +-// vwbCmdYesValid - (W) True = Command invalid, false = command acted on. ++// vwbCmdYesValid - (W) True = Command valid, false = command not handled. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. +@@ -993,12 +1079,14 @@ + bool + CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid) + { ++ // Convert any CLI commands into MI commands ++ CMIUtilString vMITextLine(WrapCliCommandIntoMiCommand(vTextLine)); ++ + vwbCmdYesValid = false; +- + bool bCmdNotInCmdFactor = false; + SMICmdData cmdData; + CMICmdMgr &rCmdMgr = CMICmdMgr::Instance(); +- if (!rCmdMgr.CmdInterpret(vTextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) ++ if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor, cmdData)) + return MIstatus::failure; + + if (vwbCmdYesValid) +@@ -1012,12 +1100,12 @@ + // Check for escape character, may be cursor control characters + // This code is not necessary for application operation, just want to keep tabs on what + // is been given to the driver to try and intepret. +- if (vTextLine.at(0) == 27) ++ if (vMITextLine.at(0) == 27) + { + CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS)); +- for (MIuint i = 0; i < vTextLine.length(); i++) ++ for (MIuint i = 0; i < vMITextLine.length(); i++) + { +- logInput += CMIUtilString::Format("%d ", vTextLine.at(i)); ++ logInput += CMIUtilString::Format("%d ", vMITextLine.at(i)); + } + m_pLog->WriteLog(logInput); + return MIstatus::success; +@@ -1030,7 +1118,7 @@ + strNotInCmdFactory = CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str()); + const CMIUtilString strNot(CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT))); + const CMIUtilString msg( +- CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vTextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); ++ CMIUtilString::Format(MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(), strNotInCmdFactory.c_str())); + const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg); + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); Index: patches/lldbmi_add_stack_info_frame.patch =================================================================== --- /dev/null +++ patches/lldbmi_add_stack_info_frame.patch @@ -0,0 +1,191 @@ +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 228417) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -11,6 +11,7 @@ + // File: MICmdCmdStack.cpp + // + // Overview: CMICmdCmdStackInfoDepth implementation. ++// CMICmdCmdStackInfoFrame interface. + // CMICmdCmdStackListFrames implementation. + // CMICmdCmdStackListArguments implementation. + // CMICmdCmdStackListLocals implementation. +@@ -158,6 +159,107 @@ + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdStackInfoFrame constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdStackInfoFrame::CMICmdCmdStackInfoFrame(void) ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "stack-info-frame"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdStackInfoFrame::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdStackInfoFrame destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdStackInfoFrame::~CMICmdCmdStackInfoFrame(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackInfoFrame::ParseArgs(void) ++{ ++ return ParseValidateCmdOptions(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackInfoFrame::Execute(void) ++{ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ lldb::SBThread sbThread = rSessionInfo.GetProcess().GetSelectedThread(); ++ MIuint nFrameId = sbThread.GetSelectedFrame().GetFrameID(); ++ ++ if (!rSessionInfo.MIResponseFormFrameInfo(sbThread, nFrameId, m_miValueTuple)) ++ return MIstatus::failure; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackInfoFrame::Acknowledge(void) ++{ ++ const CMICmnMIValueResult miValueResult("frame", m_miValueTuple); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdStackInfoFrame::CreateSelf(void) ++{ ++ return new CMICmdCmdStackInfoFrame(); ++} ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdStackListFrames constructor. + // Type: Method. + // Args: None. +Index: tools/lldb-mi/MICmdCmdStack.h +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.h (revision 228417) ++++ tools/lldb-mi/MICmdCmdStack.h (working copy) +@@ -11,6 +11,7 @@ + // File: MICmdCmdStack.h + // + // Overview: CMICmdCmdStackInfoDepth interface. ++// CMICmdCmdStackInfoFrame interface. + // CMICmdCmdStackListFrames interface. + // CMICmdCmdStackListArguments interface. + // CMICmdCmdStackListLocals interface. +@@ -36,6 +37,7 @@ + // In-house headers: + #include "MICmdBase.h" + #include "MICmnMIValueList.h" ++#include "MICmnMIValueTuple.h" + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. +@@ -73,6 +75,38 @@ + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "stack-info-frame". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 23/01/2015. ++// Changes: None. ++//-- ++class CMICmdCmdStackInfoFrame : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdStackInfoFrame(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdStackInfoFrame(void); ++ ++ // Attributes: ++ private: ++ CMICmnMIValueTuple m_miValueTuple; ++}; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "stack-list-frames". + // Gotchas: None. + // Authors: Illya Rudkin 21/03/2014. +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 228417) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -116,6 +116,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_add_stack_select_frame.patch =================================================================== --- /dev/null +++ patches/lldbmi_add_stack_select_frame.patch @@ -0,0 +1,190 @@ +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 228417) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -717,3 +717,124 @@ + { + return new CMICmdCmdStackListLocals(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdStackSelectFrame constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdStackSelectFrame::CMICmdCmdStackSelectFrame(void) ++ : m_bFrameInvalid(false) ++ , m_constStrArgFrame("frame") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "stack-select-frame"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdStackSelectFrame::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdStackSelectFrame destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdStackSelectFrame::~CMICmdCmdStackSelectFrame(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackSelectFrame::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrame, true, false))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackSelectFrame::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgFrame, Number, m_constStrArgFrame); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ lldb::SBThread sbThread = rSessionInfo.GetProcess().GetSelectedThread(); ++ ++ const MIuint nFrameId = pArgFrame->GetValue(); ++ m_bFrameInvalid = (nFrameId >= sbThread.GetNumFrames()); ++ if (m_bFrameInvalid) ++ return MIstatus::success; ++ ++ lldb::SBFrame sbFrame = sbThread.SetSelectedFrame(nFrameId); ++ m_bFrameInvalid = !sbFrame.IsValid(); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdStackSelectFrame::Acknowledge(void) ++{ ++ if (m_bFrameInvalid) ++ { ++ // MI print "%s^error,msg=\"Command '-stack-select-frame'. Frame ID invalid\"" ++ const CMICmnMIValueConst miValueConst( ++ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++ } ++ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdStackSelectFrame::CreateSelf(void) ++{ ++ return new CMICmdCmdStackSelectFrame(); ++} +Index: tools/lldb-mi/MICmdCmdStack.h +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.h (revision 228417) ++++ tools/lldb-mi/MICmdCmdStack.h (working copy) +@@ -14,6 +14,7 @@ + // CMICmdCmdStackListFrames interface. + // CMICmdCmdStackListArguments interface. + // CMICmdCmdStackListLocals interface. ++// CMICmdCmdStackSelectFrame interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -187,3 +188,36 @@ + const CMIUtilString m_constStrArgAllValues; + const CMIUtilString m_constStrArgSimpleValues; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "stack-select-frame". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 23/01/2015. ++// Changes: None. ++//-- ++class CMICmdCmdStackSelectFrame : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdStackSelectFrame(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdStackSelectFrame(void); ++ ++ // Attributes: ++ private: ++ bool m_bFrameInvalid; // True = yes invalid thread, false = thread object valid ++ const CMIUtilString m_constStrArgFrame; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 228417) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -119,6 +119,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_add_symbol_list_lines.patch =================================================================== --- /dev/null +++ patches/lldbmi_add_symbol_list_lines.patch @@ -0,0 +1,337 @@ +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 228417) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -30,6 +30,7 @@ + MICmdCmdStack.cpp + MICmdCmdSupportInfo.cpp + MICmdCmdSupportList.cpp ++ MICmdCmdSymbol.cpp + MICmdCmdTarget.cpp + MICmdCmdThread.cpp + MICmdCmdTrace.cpp +@@ -111,6 +112,7 @@ + MICmdCmdStack.cpp + MICmdCmdSupportInfo.cpp + MICmdCmdSupportList.cpp ++ MICmdCmdSymbol.cpp + MICmdCmdTarget.cpp + MICmdCmdThread.cpp + MICmdCmdTrace.cpp +Index: tools/lldb-mi/MICmdCmdSymbol.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdSymbol.cpp (revision 0) ++++ tools/lldb-mi/MICmdCmdSymbol.cpp (working copy) +@@ -0,0 +1,181 @@ ++//===-- MICmdCmdSymbol.h ----------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdSymbol.cpp ++// ++// Overview: CMICmdCmdSymbolListLines implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// Third Party Headers: ++#include ++ ++// In-house headers: ++#include "MICmdArgValFile.h" ++#include "MICmdCmdSymbol.h" ++#include "MICmnLLDBDebugSessionInfo.h" ++#include "MICmnMIResultRecord.h" ++#include "MICmnMIValueList.h" ++#include "MICmnMIValueTuple.h" ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdSymbolListLines constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines(void) ++ : m_constStrArgNameFile("file") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "symbol-list-lines"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdSymbolListLines::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdSymbolListLines destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdSymbolListLines::~CMICmdCmdSymbolListLines(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdSymbolListLines::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValFile(m_constStrArgNameFile, true, true))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Synopsis: -symbol-list-lines file ++// Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Symbol-Query.html#GDB_002fMI-Symbol-Query ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdSymbolListLines::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile); ++ ++ const CMIUtilString &strFilePath(pArgFile->GetValue()); ++ const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-table \"%s\"", strFilePath.c_str())); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult); ++ MIunused(rtn); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdSymbolListLines::Acknowledge(void) ++{ ++ if (m_lldbResult.GetErrorSize() > 0) ++ { ++ const CMICmnMIValueConst miValueConst(m_lldbResult.GetError()); ++ const CMICmnMIValueResult miValueResult("message", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ } ++ else ++ { ++ CMIUtilString::VecString_t vecLines; ++ const CMIUtilString strLldbMsg(m_lldbResult.GetOutput()); ++ const MIuint nLines(strLldbMsg.SplitLines(vecLines)); ++ ++ CMICmnMIValueList miValueList(true); ++ for (MIuint i = 1; i < nLines; ++i) ++ { ++ // String looks like: ++ // 0x0000000100000e70: /path/to/file:3[:4] ++ const CMIUtilString &rLine(vecLines[i]); ++ ++ // 0x0000000100000e70: /path/to/file:3[:4] ++ // ^^^^^^^^^^^^^^^^^^ -- pc ++ const MIuint nAddrEndPos = rLine.find(':'); ++ const CMIUtilString strAddr(rLine.substr(0, nAddrEndPos).c_str()); ++ const CMICmnMIValueConst miValueConst(strAddr); ++ const CMICmnMIValueResult miValueResult("pc", miValueConst); ++ CMICmnMIValueTuple miValueTuple(miValueResult); ++ ++ // 0x0000000100000e70: /path/to/file:3[:4] ++ // ^ -- line ++ const MIuint nLineOrColumnStartPos = rLine.rfind(':'); ++ const CMIUtilString strLineOrColumn(rLine.substr(nLineOrColumnStartPos + 1).c_str()); ++ const MIuint nPathOrLineStartPos = rLine.rfind(':', nLineOrColumnStartPos - 1); ++ const MIuint nPathOrLineLen = nLineOrColumnStartPos - nPathOrLineStartPos - 1; ++ const CMIUtilString strPathOrLine(rLine.substr(nPathOrLineStartPos + 1, nPathOrLineLen).c_str()); ++ const CMIUtilString strLine(strPathOrLine.IsNumber() ? strPathOrLine : strLineOrColumn); ++ const CMICmnMIValueConst miValueConst2(strLine); ++ const CMICmnMIValueResult miValueResult2("line", miValueConst2); ++ bool bOk = miValueTuple.Add(miValueResult2); ++ ++ bOk = bOk && miValueList.Add(miValueTuple); ++ if (!bOk) ++ return MIstatus::failure; ++ } ++ ++ // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]" ++ const CMICmnMIValueResult miValueResult("lines", miValueList); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdSymbolListLines::CreateSelf(void) ++{ ++ return new CMICmdCmdSymbolListLines(); ++} +Index: tools/lldb-mi/MICmdCmdSymbol.h +=================================================================== +--- tools/lldb-mi/MICmdCmdSymbol.h (revision 0) ++++ tools/lldb-mi/MICmdCmdSymbol.h (working copy) +@@ -0,0 +1,70 @@ ++//===-- MICmdCmdSymbol.h ----------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdSymbol.h ++// ++// Overview: CMICmdCmdSymbolListLines interface. ++// ++// To implement new MI commands derive a new command class from the command base ++// class. To enable the new command for interpretation add the new command class ++// to the command factory. The files of relevance are: ++// MICmdCommands.cpp ++// MICmdBase.h / .cpp ++// MICmdCmd.h / .cpp ++// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery ++// command class as an example. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// Third party headers: ++#include ++ ++// In-house headers: ++#include "MICmdBase.h" ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "symbol-list-lines". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 22/01/2015. ++// Changes: None. ++//-- ++class CMICmdCmdSymbolListLines : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdSymbolListLines(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdSymbolListLines(void); ++ ++ // Attributes: ++ private: ++ lldb::SBCommandReturnObject m_lldbResult; ++ const CMIUtilString m_constStrArgNameFile; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 228417) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -42,6 +42,7 @@ + #include "MICmdCmdStack.h" + #include "MICmdCmdSupportInfo.h" + #include "MICmdCmdSupportList.h" ++#include "MICmdCmdSymbol.h" + #include "MICmdCmdTarget.h" + #include "MICmdCmdThread.h" + #include "MICmdCmdTrace.h" +@@ -120,6 +121,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 228417) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -362,6 +362,19 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Split string into lines using \n and return an array of strings. ++// Type: Method. ++// Args: vwVecSplits - (W) Container of splits found in string data. ++// Return: MIuint - Number of splits found in the string data. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::SplitLines(VecString_t &vwVecSplits) const ++{ ++ return Split("\n", vwVecSplits); ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Remove '\n' from the end of string if found. It does not alter + // *this string. + // Type: Method. +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 228417) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -62,6 +62,7 @@ + CMIUtilString RemoveRepeatedCharacters(const MIchar vChar); + MIuint Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const; + MIuint SplitConsiderQuotes(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const; ++ MIuint SplitLines(VecString_t &vwVecSplits) const; + CMIUtilString StripCREndOfLine(void) const; + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; Index: patches/lldbmi_add_thread_id_field_to_signal_received_notification.patch =================================================================== --- /dev/null +++ patches/lldbmi_add_thread_id_field_to_signal_received_notification.patch @@ -0,0 +1,51 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228573) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -911,7 +911,7 @@ + } + default: + { +- // MI print "*stopped,reason=\"signal-received\",signal=\"%lld\",stopped-threads=\"all\"" ++ // MI print "*stopped,reason=\"signal-received\",signal=\"%lld\",thread-id=\"%d\",stopped-threads=\"all\"" + const CMICmnMIValueConst miValueConst("signal-received"); + const CMICmnMIValueResult miValueResult("reason", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); +@@ -919,9 +919,13 @@ + const CMICmnMIValueConst miValueConst2(strReason); + const CMICmnMIValueResult miValueResult2("signal", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); +- const CMICmnMIValueConst miValueConst3("all"); +- const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID())); ++ const CMICmnMIValueConst miValueConst3(strThreadId); ++ const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); ++ const CMICmnMIValueConst miValueConst4("all"); ++ const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult4); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); + bOk = bOk && TextToStdout("(gdb)"); + } +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 228573) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -63,7 +63,7 @@ + self.expect("\^done") + + # Test that *stopped is printed +- self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +@@ -101,7 +101,7 @@ + self.expect("\^done") + + # Test that *stopped is printed +- self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") + + # Exit + self.runCmd("-gdb-exit") Index: patches/lldbmi_clean_syntax_test.patch =================================================================== --- /dev/null +++ patches/lldbmi_clean_syntax_test.patch @@ -0,0 +1,43 @@ +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 224334) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -28,9 +28,6 @@ + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). +- prompt = "(gdb)" +- + # So that the child gets torn down after the test. + self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) + child = self.child +@@ -48,17 +45,13 @@ + child.expect("100000001\^done,bkpt={number=\"1\"") + + child.sendline("2-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("2\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + + child.sendline("0000000000000000000003-exec-continue") + child.expect("0000000000000000000003\^running") + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -74,10 +67,6 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- +- + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() Index: patches/lldbmi_cleanup_after_hangs_fix.patch =================================================================== --- /dev/null +++ patches/lldbmi_cleanup_after_hangs_fix.patch @@ -0,0 +1,94 @@ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223223) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -434,16 +434,3 @@ + + return MIstatus::success; + } +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Do some actions before exiting. +-// Type: Method. +-// Args: None. +-// Return: None. +-// Throws: None. +-//-- +-void +-CMICmnStreamStdin::OnExitHandler(void) +-{ +- m_pStdinReadHandler->InterruptReadLine(); +-} +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 223223) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -66,7 +66,6 @@ + public: + virtual bool InputAvailable(bool &vwbAvail) = 0; + virtual const MIchar *ReadLine(CMIUtilString &vwErrMsg) = 0; +- virtual void InterruptReadLine(void){}; + + /* dtor */ virtual ~IOSStdinHandler(void){}; + }; +@@ -83,7 +82,6 @@ + void SetCtrlCHit(void); + bool SetVisitor(IStreamStdin &vrVisitor); + bool SetOSStdinHandler(IOSStdinHandler &vrHandler); +- void OnExitHandler(void); + + // Overridden: + public: +Index: tools/lldb-mi/MICmnStreamStdinLinux.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinLinux.cpp (revision 223223) ++++ tools/lldb-mi/MICmnStreamStdinLinux.cpp (working copy) +@@ -214,16 +214,3 @@ + + return pText; + } +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Interrupt current and prevent new ReadLine operations. +-// Type: Method. +-// Args: None. +-// Return: None. +-// Throws: None. +-//-- +-void +-CMICmnStreamStdinLinux::InterruptReadLine(void) +-{ +- fclose(stdin); +-} +Index: tools/lldb-mi/MICmnStreamStdinLinux.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinLinux.h (revision 223223) ++++ tools/lldb-mi/MICmnStreamStdinLinux.h (working copy) +@@ -51,7 +51,6 @@ + // From CMICmnStreamStdin::IOSpecificReadStreamStdin + virtual bool InputAvailable(bool &vwbAvail); + virtual const MIchar *ReadLine(CMIUtilString &vwErrMsg); +- virtual void InterruptReadLine(void); + + // Methods: + private: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223223) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -1075,7 +1075,6 @@ + { + CMIUtilThreadLock lock(m_threadMutex); + m_bExitApp = true; +- m_rStdin.OnExitHandler(); + return; + } + +@@ -1090,7 +1089,6 @@ + } + + m_bExitApp = true; +- m_rStdin.OnExitHandler(); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_exec_arguments_fix_quotes.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_fix_quotes.patch @@ -0,0 +1,119 @@ +Index: tools/lldb-mi/MICmdArgValListBase.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValListBase.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValListBase.cpp (working copy) +@@ -156,6 +156,9 @@ + case eArgValType_StringAnything: + pOptionObj = new CMICmdArgValString(true); + break; ++ case eArgValType_StringQuotedAnything: ++ pOptionObj = new CMICmdArgValString(true, true); ++ break; + case eArgValType_ThreadGrp: + pOptionObj = new CMICmdArgValThreadGrp(); + break; +@@ -214,6 +217,9 @@ + case eArgValType_StringAnything: + bValid = CMICmdArgValString(true).IsStringArg(vrTxt); + break; ++ case eArgValType_StringQuotedAnything: ++ bValid = CMICmdArgValString(true, true).IsStringArg(vrTxt); ++ break; + case eArgValType_ThreadGrp: + bValid = CMICmdArgValThreadGrp().IsArgThreadGrp(vrTxt); + break; +Index: tools/lldb-mi/MICmdArgValListBase.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListBase.h (revision 223770) ++++ tools/lldb-mi/MICmdArgValListBase.h (working copy) +@@ -72,6 +72,7 @@ + eArgValType_StringQuotedNumber, + eArgValType_StringQuotedNumberPath, + eArgValType_StringAnything, // Accept any words for a string 'type' even if they look like --longOptions for example ++ eArgValType_StringQuotedAnything, + eArgValType_ThreadGrp, + eArgValType_count, // Always the last one + eArgValType_invalid +Index: tools/lldb-mi/MICmdArgValListOfN.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValListOfN.cpp (working copy) +@@ -113,7 +113,8 @@ + { + CMIUtilString::VecString_t vecOptions; + if ((m_eArgType == eArgValType_StringQuoted) || (m_eArgType == eArgValType_StringQuotedNumber) || +- (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything)) ++ (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything) || ++ (m_eArgType == eArgValType_StringQuotedAnything)) + { + if (vrTxt.SplitConsiderQuotes(" ", vecOptions) == 0) + return MIstatus::failure; +@@ -150,7 +151,8 @@ + { + CMIUtilString::VecString_t vecOptions; + if ((m_eArgType == eArgValType_StringQuoted) || (m_eArgType == eArgValType_StringQuotedNumber) || +- (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything)) ++ (m_eArgType == eArgValType_StringQuotedNumberPath) || (m_eArgType == eArgValType_StringAnything) || ++ (m_eArgType == eArgValType_StringQuotedAnything)) + { + if (vrTxt.SplitConsiderQuotes(" ", vecOptions) == 0) + return false; +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -41,12 +41,14 @@ + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdArgValString constructor. + // Type: Method. +-// Args: vbAnything - (R) True = Parse a string and accept anything, false = do not accept anything. ++// Args: vbAnything - (R) True = Parse a string and accept anything, false = do not accept anything. ++// vbHandleQuotes - (R) True = Parse a string surrounded by quotes spaces are not delimitors, false = only text up to ++// next delimiting space character. (Dflt = false) + // Return: None. + // Throws: None. + //-- +-CMICmdArgValString::CMICmdArgValString(const bool vbAnything) +- : m_bHandleQuotedString(false) ++CMICmdArgValString::CMICmdArgValString(const bool vbAnything, const bool vbHandleQuotes /* = false */) ++ : m_bHandleQuotedString(vbHandleQuotes) + , m_bAcceptNumbers(false) + , m_bHandleDirPaths(false) + , m_bHandleAnything(vbAnything) +@@ -417,6 +419,10 @@ + bool + CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const + { ++ // Accept anything as string word ++ if (m_bHandleAnything) ++ return true; ++ + // CODETAG_QUOTEDTEXT_SIMILAR_CODE + const MIchar cQuote = '"'; + const MIint nPos = vrTxt.find(cQuote); +Index: tools/lldb-mi/MICmdArgValString.h +=================================================================== +--- tools/lldb-mi/MICmdArgValString.h (revision 223770) ++++ tools/lldb-mi/MICmdArgValString.h (working copy) +@@ -43,7 +43,7 @@ + // Methods: + public: + /* ctor */ CMICmdArgValString(void); +- /* ctor */ CMICmdArgValString(const bool vbAnything); ++ /* ctor */ CMICmdArgValString(const bool vbAnything, const bool vbHandleQuotes = false); + /* ctor */ CMICmdArgValString(const bool vbHandleQuotes, const bool vbAcceptNumbers, const bool vbHandleDirPaths); + /* ctor */ CMICmdArgValString(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, + const bool vbHandleQuotes = false, const bool vbAcceptNumbers = false); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 223770) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -1068,7 +1068,7 @@ + CMICmdCmdExecArguments::ParseArgs(void) + { + bool bOk = m_setCmdArgs.Add( +- *(new CMICmdArgValListOfN(m_constStrArgArguments, true, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, true, true, CMICmdArgValListBase::eArgValType_StringQuotedAnything))); + return (bOk && ParseValidateCmdOptions()); + } + Index: patches/lldbmi_exec_arguments_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.patch @@ -0,0 +1,380 @@ +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 222919) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,10 +22,10 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") ++ @unittest2.skip("set target.run-args doesn't work yet") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_programargs(self): ++ """Test that 'lldb-mi --interpreter' can pass arguments to the app via set target.run-args.""" + import pexpect + self.buildDefault() + +@@ -42,25 +42,88 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("settings set target.run-args l") ++ child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to main ++ # Check argc to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"2\"") ++ ++ # Set BP on code which is only executed if "l" was passed correctly ++ self.line = line_number('main.c', '//BP_argtest') ++ child.sendline("-break-insert main.c:%d" % self.line) ++ child.expect("\^done,bkpt={number=\"2\"") ++ child.sendline("-exec-continue") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_programargsmi(self): ++ """Test that 'lldb-mi --interpreter' can pass arguments to the app using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt (seriously?!). ++ prompt = "(gdb)" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments l") ++ child.expect("\^done") ++ ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") +- child.sendline("") #FIXME: hangs here; extra return is needed ++ child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"2\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) ++ # Set BP on code which is only executed if "l" was passed correctly + self.line = line_number('main.c', '//BP_argtest') + child.sendline("-break-insert main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"2\"") +@@ -68,8 +131,6 @@ + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 222919) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vrAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vrAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,15 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vrAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vrAt) ++ { ++ return MIstatus::failure; ++ } ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vrAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 222919) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -90,8 +91,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1022,111 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, true, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++#include ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ CMIUtilString argument; ++ size_t argumentIndex = 0; ++ while (pArgArguments->GetExpectedOption(argument, argumentIndex)) ++ { ++ rSessionInfo.m_lldbTargetArguments.AppendArgument(argument.c_str()); ++ ++argumentIndex; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 222919) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 222919) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 222919) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include "lldb/Interpreter/Args.h" + + // In-house headers: + #include "MICmnBase.h" +@@ -154,6 +155,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb_private::Args m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v2.patch @@ -0,0 +1,393 @@ +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 223770) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,16 +22,13 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") ++ @unittest2.skip("requires 'session info' patch") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset set up args using -exec-arguments.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). +- prompt = "(gdb)" +- + # So that the child gets torn down after the test. + self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) + child = self.child +@@ -42,39 +39,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") +- child.sendline("") #FIXME: hangs here; extra return is needed + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' patch") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("quit") ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect("\"fourth=\\\\\\\"4th arg\\\\\\\"\"") + + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 223770) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vrAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vrAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,15 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vrAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vrAt) ++ { ++ return MIstatus::failure; ++ } ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vrAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 223770) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -90,8 +91,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1022,110 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ CMIUtilString argument; ++ size_t argumentIndex = 0; ++ while (pArgArguments->GetExpectedOption(argument, argumentIndex)) ++ { ++ rSessionInfo.m_lldbTargetArguments.AppendArgument(argument.c_str()); ++ ++argumentIndex; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 223770) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 223770) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 223770) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include "lldb/Interpreter/Args.h" + + // In-house headers: + #include "MICmnBase.h" +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb_private::Args m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v3.patch @@ -0,0 +1,393 @@ +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 224982) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,16 +22,12 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). +- prompt = "(gdb)" +- + # So that the child gets torn down after the test. + self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) + child = self.child +@@ -42,39 +38,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") +- child.sendline("") #FIXME: hangs here; extra return is needed + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' patch") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("quit") ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect_exact("\"fourth=\\\\\\\"4th arg\\\\\\\"\"") + + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 224982) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,15 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ { ++ return MIstatus::failure; ++ } ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224982) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -90,8 +91,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1022,111 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_lldbTargetArguments.Clear(); ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ rSessionInfo.m_lldbTargetArguments.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 224982) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 224982) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224982) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include "lldb/Interpreter/Args.h" + + // In-house headers: + #include "MICmnBase.h" +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb_private::Args m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v4.patch @@ -0,0 +1,391 @@ +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 224982) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,16 +22,12 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). +- prompt = "(gdb)" +- + # So that the child gets torn down after the test. + self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) + child = self.child +@@ -42,39 +38,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") +- child.sendline("") #FIXME: hangs here; extra return is needed + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' patch") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("quit") ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect_exact("\"fourth=\\\\\\\"4th arg\\\\\\\"\"") + + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 224982) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,13 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ return MIstatus::failure; ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224982) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -90,8 +91,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1022,111 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_lldbTargetArguments.Clear(); ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ rSessionInfo.m_lldbTargetArguments.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 224982) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 224982) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224982) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include "lldb/Interpreter/Args.h" + + // In-house headers: + #include "MICmnBase.h" +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb_private::Args m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v5.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v5.patch @@ -0,0 +1,715 @@ +Index: include/lldb/API/SBArgs.h +=================================================================== +--- include/lldb/API/SBArgs.h (revision 0) ++++ include/lldb/API/SBArgs.h (working copy) +@@ -0,0 +1,81 @@ ++//===-- SBArgs.h ------------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLDB_SBArgs_h_ ++#define LLDB_SBArgs_h_ ++ ++#include "lldb/API/SBDefines.h" ++ ++namespace lldb { ++ ++class SBArgs ++{ ++public: ++ SBArgs (); ++ ++ SBArgs (const SBArgs &rhs); ++ ++ ~SBArgs (); ++ ++ const lldb::SBArgs & ++ operator = (const lldb::SBArgs &rhs); ++ ++ bool ++ IsValid () const; ++ ++ size_t ++ GetArgumentCount () const; ++ ++ const char * ++ GetArgumentAtIndex (size_t idx) const; ++ ++ char ** ++ GetArgumentVector (); ++ ++ const char ** ++ GetConstArgumentVector () const; ++ ++ const char * ++ AppendArgument (const char *arg_cstr); ++ ++ void ++ Clear (); ++ ++protected: ++ ++ friend class SBTarget; ++ ++ lldb_private::Args * ++ get (); ++ ++ const lldb_private::Args * ++ get () const; ++ ++ lldb_private::Args * ++ operator -> (); ++ ++ const lldb_private::Args & ++ operator * () const; ++ ++ lldb_private::Args & ++ ref (); ++ ++ void ++ SetArgs (const lldb_private::Args &lldb_args); ++ ++private: ++ std::unique_ptr m_opaque_ap; ++ ++ void ++ CreateIfNeeded (); ++}; ++ ++} // namespace lldb ++ ++#endif // LLDB_SBArgs_h_ +Index: include/lldb/API/SBDefines.h +=================================================================== +--- include/lldb/API/SBDefines.h (revision 224992) ++++ include/lldb/API/SBDefines.h (working copy) +@@ -29,6 +29,7 @@ + namespace lldb { + + class LLDB_API SBAddress; ++class LLDB_API SBArgs; + class LLDB_API SBBlock; + class LLDB_API SBBreakpoint; + class LLDB_API SBBreakpointLocation; +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 224992) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -1047,7 +1047,13 @@ + + lldb::addr_t + GetStackRedZoneSize(); +- ++ ++ lldb::SBArgs ++ GetRunArguments () const; ++ ++ bool ++ SetRunArguments (const lldb::SBArgs &args); ++ + protected: + friend class SBAddress; + friend class SBBlock; +Index: source/API/CMakeLists.txt +=================================================================== +--- source/API/CMakeLists.txt (revision 224992) ++++ source/API/CMakeLists.txt (working copy) +@@ -5,6 +5,7 @@ + # well (where appropriate). + add_lldb_library(lldbAPI + SBAddress.cpp ++ SBArgs.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp +Index: source/API/SBArgs.cpp +=================================================================== +--- source/API/SBArgs.cpp (revision 0) ++++ source/API/SBArgs.cpp (working copy) +@@ -0,0 +1,146 @@ ++//===-- SBArgs.cpp -------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "lldb/API/SBArgs.h" ++#include "lldb/Interpreter/Args.h" ++ ++ ++using namespace lldb; ++using namespace lldb_private; ++ ++ ++SBArgs::SBArgs () : ++ m_opaque_ap () ++{ ++} ++ ++SBArgs::SBArgs (const SBArgs &rhs) : ++ m_opaque_ap () ++{ ++ if (rhs.IsValid()) ++ m_opaque_ap.reset (new Args(*rhs)); ++} ++ ++SBArgs::~SBArgs () ++{ ++} ++ ++const SBArgs & ++SBArgs::operator = (const SBArgs &rhs) ++{ ++ if (rhs.IsValid()) ++ { ++ if (m_opaque_ap.get()) ++ *m_opaque_ap = *rhs; ++ else ++ m_opaque_ap.reset (new Args(*rhs)); ++ } ++ else ++ m_opaque_ap.reset(); ++ ++ return *this; ++} ++ ++bool ++SBArgs::IsValid () const ++{ ++ return m_opaque_ap.get() != NULL; ++} ++ ++void ++SBArgs::SetArgs (const Args &lldb_args) ++{ ++ CreateIfNeeded (); ++ *m_opaque_ap = lldb_args; ++} ++ ++size_t ++SBArgs::GetArgumentCount () const ++{ ++ if (m_opaque_ap.get()) ++ return m_opaque_ap->GetArgumentCount(); ++ return 0; ++} ++ ++const char * ++SBArgs::GetArgumentAtIndex (size_t idx) const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentAtIndex(idx); ++ return NULL; ++} ++ ++char ** ++SBArgs::GetArgumentVector () ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentVector(); ++ return NULL; ++} ++ ++const char ** ++SBArgs::GetConstArgumentVector () const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetConstArgumentVector(); ++ return NULL; ++} ++ ++const char * ++SBArgs::AppendArgument (const char *arg_cstr) ++{ ++ CreateIfNeeded (); ++ return m_opaque_ap->AppendArgument(arg_cstr); ++} ++ ++void ++SBArgs::Clear () ++{ ++ if (m_opaque_ap) ++ m_opaque_ap->Clear(); ++} ++ ++Args * ++SBArgs::get () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args * ++SBArgs::get () const ++{ ++ return m_opaque_ap.get(); ++} ++ ++Args * ++SBArgs::operator -> () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args & ++SBArgs::operator * () const ++{ ++ // Be sure to call "IsValid()" before calling this function or it will crash ++ return *m_opaque_ap; ++} ++ ++Args & ++SBArgs::ref () ++{ ++ CreateIfNeeded(); ++ return *m_opaque_ap; ++} ++ ++void ++SBArgs::CreateIfNeeded () ++{ ++ if (m_opaque_ap.get() == NULL) ++ m_opaque_ap.reset(new Args()); ++} +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 224992) ++++ source/API/SBTarget.cpp (working copy) +@@ -13,6 +13,7 @@ + + #include "lldb/lldb-public.h" + ++#include "lldb/API/SBArgs.h" + #include "lldb/API/SBDebugger.h" + #include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBExpressionOptions.h" +@@ -2929,3 +2930,29 @@ + return 0; + } + ++SBArgs ++SBTarget::GetRunArguments () const ++{ ++ SBArgs sb_args; ++ TargetSP target_sp(GetSP()); ++ if (target_sp) ++ { ++ Args args; ++ if (m_opaque_sp->GetRunArguments(args)) ++ sb_args.SetArgs (args); ++ } ++ return sb_args; ++} ++ ++bool ++SBTarget::SetRunArguments (const SBArgs &args) ++{ ++ bool result = false; ++ TargetSP target_sp(GetSP()); ++ if (target_sp && args.IsValid()) ++ { ++ m_opaque_sp->SetRunArguments(*args.get()); ++ result = true; ++ } ++ return result; ++} +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 224992) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,10 +22,9 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +@@ -39,36 +38,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' and 'CLI support' patches") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect_exact("\"fourth=\\\"4th arg\\\"\"") ++ + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 224992) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,13 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ return MIstatus::failure; ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -27,6 +28,7 @@ + //-- + + // Third Party Headers: ++#include + #include + #include + #include +@@ -90,8 +92,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1023,113 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ lldb::SBArgs sbArgs; ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ sbArgs.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_lldbTargetArguments = sbArgs; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 224992) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -24,6 +24,7 @@ + // Third party headers: + #include + #include ++#include + #include + #include + #include +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb::SBArgs m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v6.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v6.patch @@ -0,0 +1,715 @@ +Index: include/lldb/API/SBArgs.h +=================================================================== +--- include/lldb/API/SBArgs.h (revision 0) ++++ include/lldb/API/SBArgs.h (working copy) +@@ -0,0 +1,81 @@ ++//===-- SBArgs.h ------------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLDB_SBArgs_h_ ++#define LLDB_SBArgs_h_ ++ ++#include "lldb/API/SBDefines.h" ++ ++namespace lldb { ++ ++class SBArgs ++{ ++public: ++ SBArgs (); ++ ++ SBArgs (const SBArgs &rhs); ++ ++ ~SBArgs (); ++ ++ const lldb::SBArgs & ++ operator = (const lldb::SBArgs &rhs); ++ ++ bool ++ IsValid () const; ++ ++ size_t ++ GetArgumentCount () const; ++ ++ const char * ++ GetArgumentAtIndex (size_t idx) const; ++ ++ char ** ++ GetArgumentVector (); ++ ++ const char ** ++ GetConstArgumentVector () const; ++ ++ const char * ++ AppendArgument (const char *arg_cstr); ++ ++ void ++ Clear (); ++ ++protected: ++ ++ friend class SBTarget; ++ ++ lldb_private::Args * ++ get (); ++ ++ const lldb_private::Args * ++ get () const; ++ ++ lldb_private::Args * ++ operator -> (); ++ ++ const lldb_private::Args & ++ operator * () const; ++ ++ lldb_private::Args & ++ ref (); ++ ++ void ++ SetArgs (const lldb_private::Args &lldb_args); ++ ++private: ++ std::unique_ptr m_opaque_ap; ++ ++ void ++ CreateIfNeeded (); ++}; ++ ++} // namespace lldb ++ ++#endif // LLDB_SBArgs_h_ +Index: include/lldb/API/SBDefines.h +=================================================================== +--- include/lldb/API/SBDefines.h (revision 225039) ++++ include/lldb/API/SBDefines.h (working copy) +@@ -29,6 +29,7 @@ + namespace lldb { + + class LLDB_API SBAddress; ++class LLDB_API SBArgs; + class LLDB_API SBBlock; + class LLDB_API SBBreakpoint; + class LLDB_API SBBreakpointLocation; +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 225039) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -1047,7 +1047,13 @@ + + lldb::addr_t + GetStackRedZoneSize(); +- ++ ++ lldb::SBArgs ++ GetRunArguments () const; ++ ++ bool ++ SetRunArguments (const lldb::SBArgs &args); ++ + protected: + friend class SBAddress; + friend class SBBlock; +Index: source/API/CMakeLists.txt +=================================================================== +--- source/API/CMakeLists.txt (revision 225039) ++++ source/API/CMakeLists.txt (working copy) +@@ -5,6 +5,7 @@ + # well (where appropriate). + add_lldb_library(lldbAPI + SBAddress.cpp ++ SBArgs.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp +Index: source/API/SBArgs.cpp +=================================================================== +--- source/API/SBArgs.cpp (revision 0) ++++ source/API/SBArgs.cpp (working copy) +@@ -0,0 +1,146 @@ ++//===-- SBArgs.cpp -------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "lldb/API/SBArgs.h" ++#include "lldb/Interpreter/Args.h" ++ ++ ++using namespace lldb; ++using namespace lldb_private; ++ ++ ++SBArgs::SBArgs () : ++ m_opaque_ap () ++{ ++} ++ ++SBArgs::SBArgs (const SBArgs &rhs) : ++ m_opaque_ap () ++{ ++ if (rhs.IsValid()) ++ m_opaque_ap.reset (new Args(*rhs)); ++} ++ ++SBArgs::~SBArgs () ++{ ++} ++ ++const SBArgs & ++SBArgs::operator = (const SBArgs &rhs) ++{ ++ if (rhs.IsValid()) ++ { ++ if (m_opaque_ap.get()) ++ *m_opaque_ap = *rhs; ++ else ++ m_opaque_ap.reset (new Args(*rhs)); ++ } ++ else ++ m_opaque_ap.reset(); ++ ++ return *this; ++} ++ ++bool ++SBArgs::IsValid () const ++{ ++ return m_opaque_ap.get() != NULL; ++} ++ ++void ++SBArgs::SetArgs (const Args &lldb_args) ++{ ++ CreateIfNeeded (); ++ *m_opaque_ap = lldb_args; ++} ++ ++size_t ++SBArgs::GetArgumentCount () const ++{ ++ if (m_opaque_ap.get()) ++ return m_opaque_ap->GetArgumentCount(); ++ return 0; ++} ++ ++const char * ++SBArgs::GetArgumentAtIndex (size_t idx) const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentAtIndex(idx); ++ return NULL; ++} ++ ++char ** ++SBArgs::GetArgumentVector () ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentVector(); ++ return NULL; ++} ++ ++const char ** ++SBArgs::GetConstArgumentVector () const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetConstArgumentVector(); ++ return NULL; ++} ++ ++const char * ++SBArgs::AppendArgument (const char *arg_cstr) ++{ ++ CreateIfNeeded (); ++ return m_opaque_ap->AppendArgument(arg_cstr); ++} ++ ++void ++SBArgs::Clear () ++{ ++ if (m_opaque_ap) ++ m_opaque_ap->Clear(); ++} ++ ++Args * ++SBArgs::get () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args * ++SBArgs::get () const ++{ ++ return m_opaque_ap.get(); ++} ++ ++Args * ++SBArgs::operator -> () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args & ++SBArgs::operator * () const ++{ ++ // Be sure to call "IsValid()" before calling this function or it will crash ++ return *m_opaque_ap; ++} ++ ++Args & ++SBArgs::ref () ++{ ++ CreateIfNeeded(); ++ return *m_opaque_ap; ++} ++ ++void ++SBArgs::CreateIfNeeded () ++{ ++ if (m_opaque_ap.get() == NULL) ++ m_opaque_ap.reset(new Args()); ++} +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 225039) ++++ source/API/SBTarget.cpp (working copy) +@@ -13,6 +13,7 @@ + + #include "lldb/lldb-public.h" + ++#include "lldb/API/SBArgs.h" + #include "lldb/API/SBDebugger.h" + #include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBExpressionOptions.h" +@@ -2929,3 +2930,29 @@ + return 0; + } + ++SBArgs ++SBTarget::GetRunArguments () const ++{ ++ SBArgs sb_args; ++ TargetSP target_sp(GetSP()); ++ if (target_sp) ++ { ++ Args args; ++ if (m_opaque_sp->GetRunArguments(args)) ++ sb_args.SetArgs(args); ++ } ++ return sb_args; ++} ++ ++bool ++SBTarget::SetRunArguments (const SBArgs &args) ++{ ++ bool result = false; ++ TargetSP target_sp(GetSP()); ++ if (target_sp && args.IsValid()) ++ { ++ m_opaque_sp->SetRunArguments(*args.get()); ++ result = true; ++ } ++ return result; ++} +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 225039) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,10 +22,9 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +@@ -39,36 +38,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' and 'CLI support' patches") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect_exact("\"fourth=\\\"4th arg\\\"\"") ++ + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 225039) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,13 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ return MIstatus::failure; ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 225039) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -27,6 +28,7 @@ + //-- + + // Third Party Headers: ++#include + #include + #include + #include +@@ -90,8 +92,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1023,113 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ lldb::SBArgs sbArgs; ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ sbArgs.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_lldbTargetArguments = sbArgs; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 225039) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 225039) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 225039) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -24,6 +24,7 @@ + // Third party headers: + #include + #include ++#include + #include + #include + #include +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb::SBArgs m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v7.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v7.patch @@ -0,0 +1,695 @@ +Index: include/lldb/API/SBArgs.h +=================================================================== +--- include/lldb/API/SBArgs.h (revision 0) ++++ include/lldb/API/SBArgs.h (working copy) +@@ -0,0 +1,66 @@ ++//===-- SBArgs.h ------------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLDB_SBArgs_h_ ++#define LLDB_SBArgs_h_ ++ ++#include "lldb/API/SBDefines.h" ++ ++namespace lldb ++{ ++ ++class SBArgs ++{ ++ public: ++ SBArgs(); ++ ++ SBArgs(const SBArgs &rhs); ++ ++ ~SBArgs(); ++ ++ const lldb::SBArgs &operator=(const lldb::SBArgs &rhs); ++ ++ bool IsValid() const; ++ ++ size_t GetArgumentCount() const; ++ ++ const char *GetArgumentAtIndex(size_t idx) const; ++ ++ char **GetArgumentVector(); ++ ++ const char **GetConstArgumentVector() const; ++ ++ const char *AppendArgument(const char *arg_cstr); ++ ++ void Clear(); ++ ++ protected: ++ friend class SBTarget; ++ ++ lldb_private::Args *get(); ++ ++ const lldb_private::Args *get() const; ++ ++ lldb_private::Args *operator->(); ++ ++ const lldb_private::Args &operator*() const; ++ ++ lldb_private::Args &ref(); ++ ++ void SetArgs(const lldb_private::Args &lldb_args); ++ ++ private: ++ std::unique_ptr m_opaque_ap; ++ ++ void CreateIfNeeded(); ++}; ++ ++} // namespace lldb ++ ++#endif // LLDB_SBArgs_h_ +Index: include/lldb/API/SBDefines.h +=================================================================== +--- include/lldb/API/SBDefines.h (revision 225982) ++++ include/lldb/API/SBDefines.h (working copy) +@@ -29,6 +29,7 @@ + namespace lldb { + + class LLDB_API SBAddress; ++class LLDB_API SBArgs; + class LLDB_API SBBlock; + class LLDB_API SBBreakpoint; + class LLDB_API SBBreakpointLocation; +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 225982) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -1047,7 +1047,13 @@ + + lldb::addr_t + GetStackRedZoneSize(); +- ++ ++ lldb::SBArgs ++ GetRunArguments () const; ++ ++ bool ++ SetRunArguments (const lldb::SBArgs &args); ++ + protected: + friend class SBAddress; + friend class SBBlock; +Index: source/API/CMakeLists.txt +=================================================================== +--- source/API/CMakeLists.txt (revision 225982) ++++ source/API/CMakeLists.txt (working copy) +@@ -5,6 +5,7 @@ + # well (where appropriate). + add_lldb_library(lldbAPI + SBAddress.cpp ++ SBArgs.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp +Index: source/API/SBArgs.cpp +=================================================================== +--- source/API/SBArgs.cpp (revision 0) ++++ source/API/SBArgs.cpp (working copy) +@@ -0,0 +1,141 @@ ++//===-- SBArgs.cpp -------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "lldb/API/SBArgs.h" ++#include "lldb/Interpreter/Args.h" ++ ++using namespace lldb; ++using namespace lldb_private; ++ ++SBArgs::SBArgs() ++ : m_opaque_ap() ++{ ++} ++ ++SBArgs::SBArgs(const SBArgs &rhs) ++ : m_opaque_ap() ++{ ++ if (rhs.IsValid()) ++ m_opaque_ap.reset(new Args(*rhs)); ++} ++ ++SBArgs::~SBArgs() ++{ ++} ++ ++const SBArgs &SBArgs::operator=(const SBArgs &rhs) ++{ ++ if (rhs.IsValid()) ++ { ++ if (m_opaque_ap.get()) ++ *m_opaque_ap = *rhs; ++ else ++ m_opaque_ap.reset(new Args(*rhs)); ++ } ++ else ++ m_opaque_ap.reset(); ++ ++ return *this; ++} ++ ++bool ++SBArgs::IsValid() const ++{ ++ return m_opaque_ap.get() != NULL; ++} ++ ++void ++SBArgs::SetArgs(const Args &lldb_args) ++{ ++ CreateIfNeeded(); ++ *m_opaque_ap = lldb_args; ++} ++ ++size_t ++SBArgs::GetArgumentCount() const ++{ ++ if (m_opaque_ap.get()) ++ return m_opaque_ap->GetArgumentCount(); ++ return 0; ++} ++ ++const char * ++SBArgs::GetArgumentAtIndex(size_t idx) const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentAtIndex(idx); ++ return NULL; ++} ++ ++char ** ++SBArgs::GetArgumentVector() ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentVector(); ++ return NULL; ++} ++ ++const char ** ++SBArgs::GetConstArgumentVector() const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetConstArgumentVector(); ++ return NULL; ++} ++ ++const char * ++SBArgs::AppendArgument(const char *arg_cstr) ++{ ++ CreateIfNeeded(); ++ return m_opaque_ap->AppendArgument(arg_cstr); ++} ++ ++void ++SBArgs::Clear() ++{ ++ if (m_opaque_ap) ++ m_opaque_ap->Clear(); ++} ++ ++Args * ++SBArgs::get() ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args * ++SBArgs::get() const ++{ ++ return m_opaque_ap.get(); ++} ++ ++Args *SBArgs::operator->() ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args &SBArgs::operator*() const ++{ ++ // Be sure to call "IsValid()" before calling this function or it will crash ++ return *m_opaque_ap; ++} ++ ++Args & ++SBArgs::ref() ++{ ++ CreateIfNeeded(); ++ return *m_opaque_ap; ++} ++ ++void ++SBArgs::CreateIfNeeded() ++{ ++ if (m_opaque_ap.get() == NULL) ++ m_opaque_ap.reset(new Args()); ++} +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 225982) ++++ source/API/SBTarget.cpp (working copy) +@@ -13,6 +13,7 @@ + + #include "lldb/lldb-public.h" + ++#include "lldb/API/SBArgs.h" + #include "lldb/API/SBDebugger.h" + #include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBExpressionOptions.h" +@@ -2929,3 +2930,29 @@ + return 0; + } + ++SBArgs ++SBTarget::GetRunArguments () const ++{ ++ SBArgs sb_args; ++ TargetSP target_sp(GetSP()); ++ if (target_sp) ++ { ++ Args args; ++ if (m_opaque_sp->GetRunArguments(args)) ++ sb_args.SetArgs(args); ++ } ++ return sb_args; ++} ++ ++bool ++SBTarget::SetRunArguments (const SBArgs &args) ++{ ++ bool result = false; ++ TargetSP target_sp(GetSP()); ++ if (target_sp && args.IsValid()) ++ { ++ m_opaque_sp->SetRunArguments(*args.get()); ++ result = true; ++ } ++ return result; ++} +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 225982) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,10 +22,9 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +@@ -39,36 +38,99 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.skip("requires 'quotes' and 'CLI support' patches") ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("print argv[1]") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("print argv[2]") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("print argv[3]") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("print argv[4]") ++ child.expect_exact("\"fourth=\\\"4th arg\\\"\"") ++ + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 225982) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,13 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ return MIstatus::failure; ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -27,6 +28,7 @@ + //-- + + // Third Party Headers: ++#include + #include + #include + #include +@@ -90,8 +92,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTargetArguments.GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1023,113 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ lldb::SBArgs sbArgs; ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ sbArgs.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_lldbTargetArguments = sbArgs; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 225982) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 225982) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -24,6 +24,7 @@ + // Third party headers: + #include + #include ++#include + #include + #include + #include +@@ -167,6 +168,7 @@ + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; ++ lldb::SBArgs m_lldbTargetArguments; + + // These are keys that can be used to access the shared data map + // Note: This list is expected to grow and will be moved and abstracted in the future. Index: patches/lldbmi_exec_arguments_support.v8.patch =================================================================== --- /dev/null +++ patches/lldbmi_exec_arguments_support.v8.patch @@ -0,0 +1,710 @@ +Index: include/lldb/API/SBArgs.h +=================================================================== +--- include/lldb/API/SBArgs.h (revision 0) ++++ include/lldb/API/SBArgs.h (working copy) +@@ -0,0 +1,83 @@ ++//===-- SBArgs.h ------------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLDB_SBArgs_h_ ++#define LLDB_SBArgs_h_ ++ ++#include "lldb/API/SBDefines.h" ++ ++namespace lldb { ++ ++class SBArgs ++{ ++public: ++ SBArgs (); ++ ++ SBArgs (bool force_create); ++ ++ SBArgs (const SBArgs &rhs); ++ ++ ~SBArgs (); ++ ++ const lldb::SBArgs & ++ operator = (const lldb::SBArgs &rhs); ++ ++ bool ++ IsValid () const; ++ ++ size_t ++ GetArgumentCount () const; ++ ++ const char * ++ GetArgumentAtIndex (size_t idx) const; ++ ++ char ** ++ GetArgumentVector (); ++ ++ const char ** ++ GetConstArgumentVector () const; ++ ++ const char * ++ AppendArgument (const char *arg_cstr); ++ ++ void ++ Clear (); ++ ++protected: ++ ++ friend class SBTarget; ++ ++ lldb_private::Args * ++ get (); ++ ++ const lldb_private::Args * ++ get () const; ++ ++ lldb_private::Args * ++ operator -> (); ++ ++ const lldb_private::Args & ++ operator * () const; ++ ++ lldb_private::Args & ++ ref (); ++ ++ void ++ SetArgs (const lldb_private::Args &lldb_args); ++ ++private: ++ std::unique_ptr m_opaque_ap; ++ ++ void ++ CreateIfNeeded (); ++}; ++ ++} // namespace lldb ++ ++#endif // LLDB_SBArgs_h_ +Index: include/lldb/API/SBDefines.h +=================================================================== +--- include/lldb/API/SBDefines.h (revision 226488) ++++ include/lldb/API/SBDefines.h (working copy) +@@ -29,6 +29,7 @@ + namespace lldb { + + class LLDB_API SBAddress; ++class LLDB_API SBArgs; + class LLDB_API SBBlock; + class LLDB_API SBBreakpoint; + class LLDB_API SBBreakpointLocation; +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 226488) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -1047,7 +1047,13 @@ + + lldb::addr_t + GetStackRedZoneSize(); +- ++ ++ lldb::SBArgs ++ GetRunArguments () const; ++ ++ bool ++ SetRunArguments (const lldb::SBArgs &args); ++ + protected: + friend class SBAddress; + friend class SBBlock; +Index: source/API/CMakeLists.txt +=================================================================== +--- source/API/CMakeLists.txt (revision 226488) ++++ source/API/CMakeLists.txt (working copy) +@@ -5,6 +5,7 @@ + # well (where appropriate). + add_lldb_library(lldbAPI + SBAddress.cpp ++ SBArgs.cpp + SBBlock.cpp + SBBreakpoint.cpp + SBBreakpointLocation.cpp +Index: source/API/SBArgs.cpp +=================================================================== +--- source/API/SBArgs.cpp (revision 0) ++++ source/API/SBArgs.cpp (working copy) +@@ -0,0 +1,153 @@ ++//===-- SBArgs.cpp -------------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "lldb/API/SBArgs.h" ++#include "lldb/Interpreter/Args.h" ++ ++ ++using namespace lldb; ++using namespace lldb_private; ++ ++ ++SBArgs::SBArgs () : ++ m_opaque_ap () ++{ ++} ++ ++SBArgs::SBArgs (bool force_create) : ++ m_opaque_ap () ++{ ++ if (force_create) ++ m_opaque_ap.reset (new Args()); ++} ++ ++SBArgs::SBArgs (const SBArgs &rhs) : ++ m_opaque_ap () ++{ ++ if (rhs.IsValid()) ++ m_opaque_ap.reset (new Args(*rhs)); ++} ++ ++SBArgs::~SBArgs () ++{ ++} ++ ++const SBArgs & ++SBArgs::operator = (const SBArgs &rhs) ++{ ++ if (rhs.IsValid()) ++ { ++ if (m_opaque_ap.get()) ++ *m_opaque_ap = *rhs; ++ else ++ m_opaque_ap.reset (new Args(*rhs)); ++ } ++ else ++ m_opaque_ap.reset(); ++ ++ return *this; ++} ++ ++bool ++SBArgs::IsValid () const ++{ ++ return m_opaque_ap.get() != NULL; ++} ++ ++void ++SBArgs::SetArgs (const Args &lldb_args) ++{ ++ CreateIfNeeded (); ++ *m_opaque_ap = lldb_args; ++} ++ ++size_t ++SBArgs::GetArgumentCount () const ++{ ++ if (m_opaque_ap.get()) ++ return m_opaque_ap->GetArgumentCount(); ++ return 0; ++} ++ ++const char * ++SBArgs::GetArgumentAtIndex (size_t idx) const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentAtIndex(idx); ++ return NULL; ++} ++ ++char ** ++SBArgs::GetArgumentVector () ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetArgumentVector(); ++ return NULL; ++} ++ ++const char ** ++SBArgs::GetConstArgumentVector () const ++{ ++ if (m_opaque_ap) ++ return m_opaque_ap->GetConstArgumentVector(); ++ return NULL; ++} ++ ++const char * ++SBArgs::AppendArgument (const char *arg_cstr) ++{ ++ CreateIfNeeded (); ++ return m_opaque_ap->AppendArgument(arg_cstr); ++} ++ ++void ++SBArgs::Clear () ++{ ++ if (m_opaque_ap) ++ m_opaque_ap->Clear(); ++} ++ ++Args * ++SBArgs::get () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args * ++SBArgs::get () const ++{ ++ return m_opaque_ap.get(); ++} ++ ++Args * ++SBArgs::operator -> () ++{ ++ return m_opaque_ap.get(); ++} ++ ++const Args & ++SBArgs::operator * () const ++{ ++ // Be sure to call "IsValid()" before calling this function or it will crash ++ return *m_opaque_ap; ++} ++ ++Args & ++SBArgs::ref () ++{ ++ CreateIfNeeded(); ++ return *m_opaque_ap; ++} ++ ++void ++SBArgs::CreateIfNeeded () ++{ ++ if (m_opaque_ap.get() == NULL) ++ m_opaque_ap.reset(new Args()); ++} +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 226488) ++++ source/API/SBTarget.cpp (working copy) +@@ -13,6 +13,7 @@ + + #include "lldb/lldb-public.h" + ++#include "lldb/API/SBArgs.h" + #include "lldb/API/SBDebugger.h" + #include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBExpressionOptions.h" +@@ -2929,3 +2930,29 @@ + return 0; + } + ++SBArgs ++SBTarget::GetRunArguments () const ++{ ++ SBArgs sb_args; ++ TargetSP target_sp(GetSP()); ++ if (target_sp) ++ { ++ Args args; ++ if (m_opaque_sp->GetRunArguments(args)) ++ sb_args.SetArgs(args); ++ } ++ return sb_args; ++} ++ ++bool ++SBTarget::SetRunArguments (const SBArgs &args) ++{ ++ bool result = false; ++ TargetSP target_sp(GetSP()); ++ if (target_sp && args.IsValid()) ++ { ++ m_opaque_sp->SetRunArguments(*args.get()); ++ result = true; ++ } ++ return result; ++} +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 226488) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -22,10 +22,9 @@ + except: + pass + +- @unittest2.skip("lldb-mi can't pass params to app.") + @lldbmi_test +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" ++ def test_lldbmi_clearargs(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" + import pexpect + self.buildDefault() + +@@ -39,36 +38,98 @@ + child.logfile_send = f_send + child.logfile_read = f_read + +- child.sendline("-file-exec-and-symbols " + self.myexe) ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) + child.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ # Set arguments ++ child.sendline("-exec-arguments foo bar baz") ++ child.expect("\^done") ++ child.sendline("-exec-arguments") ++ child.expect("\^done") + +- #run to main ++ # Run to main + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed ++ # Check argc to see if arg passed + child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ child.expect("\^done,value=\"1\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_setargs(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Set arguments ++ child.sendline("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") + child.expect("\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ # Check argc and argv to see if arg passed ++ child.sendline("-data-evaluate-expression argc") ++ child.expect("\^done,value=\"5\"") ++ #child.sendline("-data-evaluate-expression argv[1]") ++ #child.expect("\^done,value=\"--arg1\"") ++ child.sendline("-interpreter-exec command \"print argv[1]\"") ++ child.expect("\"--arg1\"") ++ #child.sendline("-data-evaluate-expression argv[2]") ++ #child.expect("\^done,value=\"2nd arg\"") ++ child.sendline("-interpreter-exec command \"print argv[2]\"") ++ child.expect("\"2nd arg\"") ++ #child.sendline("-data-evaluate-expression argv[3]") ++ #child.expect("\^done,value=\"third_arg\"") ++ child.sendline("-interpreter-exec command \"print argv[3]\"") ++ child.expect("\"third_arg\"") ++ #child.sendline("-data-evaluate-expression argv[4]") ++ #child.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ child.sendline("-interpreter-exec command \"print argv[4]\"") ++ child.expect_exact("\"fourth=\\\"4th arg\\\"\"") ++ + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None + child.logfile_read = None +- ++ + with open('child_send.txt', 'r') as fs: + if self.TraceOn(): + print "\n\nContents of child_send.txt:" +Index: tools/lldb-mi/MICmdArgValListOfN.h +=================================================================== +--- tools/lldb-mi/MICmdArgValListOfN.h (revision 226488) ++++ tools/lldb-mi/MICmdArgValListOfN.h (working copy) +@@ -56,7 +56,7 @@ + const ArgValType_e veType); + // + const VecArgObjPtr_t &GetExpectedOptions(void) const; +- template bool GetExpectedOption(T2 &vrwValue) const; ++ template bool GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt = 0) const; + + // Overridden: + public: +@@ -76,6 +76,7 @@ + // parsed from the command's options string. + // Type: Template method. + // Args: vrwValue - (W) Templated type return value. ++// vnAt - (R) Value at the specific position. + // T1 - The argument value's class type of the data hold in the list of options. + // T2 - The type pf the variable which holds the value wanted. + // Return: MIstatus::success - Functional succeeded. +@@ -84,10 +85,13 @@ + //-- + template + bool +-CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue) const ++CMICmdArgValListOfN::GetExpectedOption(T2 &vrwValue, const VecArgObjPtr_t::size_type vnAt) const + { + const VecArgObjPtr_t &rVecOptions(GetExpectedOptions()); +- VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin(); ++ if (rVecOptions.size() <= vnAt) ++ return MIstatus::failure; ++ ++ VecArgObjPtr_t::const_iterator it2 = rVecOptions.begin() + vnAt; + if (it2 != rVecOptions.end()) + { + const T1 *pOption = static_cast(*it2); +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 226488) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction implementation. + // CMICmdCmdExecFinish implementation. + // CMICmdCmdExecInterrupt implementation. ++// CMICmdCmdExecArguments implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +@@ -27,6 +28,7 @@ + //-- + + // Third Party Headers: ++#include + #include + #include + #include +@@ -90,8 +92,10 @@ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBError error; + lldb::SBStream errMsg; +- uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, ++ const uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; ++ lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, ++ rSessionInfo.m_lldbTarget.GetRunArguments().GetConstArgumentVector(), ++ nullptr, nullptr, nullptr, nullptr, + nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) +@@ -1019,3 +1023,120 @@ + { + return new CMICmdCmdExecInterrupt(); + } ++ ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++//--------------------------------------------------------------------------------------- ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::CMICmdCmdExecArguments(void) ++ : m_constStrArgArguments("arguments") ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "exec-arguments"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdExecArguments::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdExecArguments destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdExecArguments::~CMICmdCmdExecArguments(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgArguments, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgArguments, ListOfN, m_constStrArgArguments); ++ ++ lldb::SBArgs sbArgs(true); ++ CMIUtilString strArg; ++ size_t nArgIndex = 0; ++ while (pArgArguments->GetExpectedOption(strArg, nArgIndex)) ++ { ++ sbArgs.AppendArgument(strArg.c_str()); ++ ++nArgIndex; ++ } ++ ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ lldb::SBTarget sbTarget = rSessionInfo.m_lldbTarget; ++ if (!sbTarget.IsValid()) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ ++ sbTarget.SetRunArguments(sbArgs); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdExecArguments::Acknowledge(void) ++{ ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdExecArguments::CreateSelf(void) ++{ ++ return new CMICmdCmdExecArguments(); ++} +Index: tools/lldb-mi/MICmdCmdExec.h +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.h (revision 226488) ++++ tools/lldb-mi/MICmdCmdExec.h (working copy) +@@ -18,6 +18,7 @@ + // CMICmdCmdExecStepInstruction interface. + // CMICmdCmdExecFinish interface. + // CMICmdCmdExecInterrupt interface. ++// CMICmdCmdExecArguments interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class +@@ -307,3 +308,35 @@ + private: + lldb::SBCommandReturnObject m_lldbResult; + }; ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "exec-arguments". ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 25/11/2014. ++// Changes: None. ++//-- ++class CMICmdCmdExecArguments : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdExecArguments(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdExecArguments(void); ++ ++ // Attributes: ++ private: ++ const CMIUtilString m_constStrArgArguments; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 226488) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -98,6 +98,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_fix_c_str_bug.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_c_str_bug.patch @@ -0,0 +1,315 @@ +Index: tools/lldb-mi/MICmdArgValOptionLong.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValOptionLong.cpp (revision 224200) ++++ tools/lldb-mi/MICmdArgValOptionLong.cpp (working copy) +@@ -273,7 +273,7 @@ + if (vrTxt.length() < 3) + return false; + +- const CMIUtilString strArg = vrTxt.substr(2).c_str(); ++ const CMIUtilString strArg(vrTxt.substr(2)); + if (strArg.IsNumber()) + return false; + +@@ -305,7 +305,7 @@ + bool + CMICmdArgValOptionLong::ArgNameMatch(const CMIUtilString &vrTxt) const + { +- const CMIUtilString strArg = vrTxt.substr(2).c_str(); ++ const CMIUtilString strArg(vrTxt.substr(2)); + return (strArg == GetName()); + } + +Index: tools/lldb-mi/MICmdArgValOptionShort.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValOptionShort.cpp (revision 224200) ++++ tools/lldb-mi/MICmdArgValOptionShort.cpp (working copy) +@@ -127,6 +127,6 @@ + bool + CMICmdArgValOptionShort::ArgNameMatch(const CMIUtilString &vrTxt) const + { +- const CMIUtilString strArg = vrTxt.substr(1).c_str(); ++ const CMIUtilString strArg(vrTxt.substr(1)); + return (strArg == GetName()); + } +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 224200) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -227,12 +227,12 @@ + return MIstatus::failure; + + // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); ++ const CMIUtilString strQuotedTxt(strOptions.substr(nPos, nPos2 - nPos + 1)); + if (vrwArgContext.RemoveArg(strQuotedTxt)) + { + m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1); + return MIstatus::success; + } + +@@ -284,7 +284,7 @@ + return MIstatus::failure; + + // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); ++ const CMIUtilString strQuotedTxt(strOptions.substr(nPos, nPosQuote2 - nPos + 1)); + if (vrwArgContext.RemoveArg(strQuotedTxt)) + { + m_bFound = true; +@@ -331,7 +331,7 @@ + return MIstatus::failure; + + // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); ++ const CMIUtilString strQuotedTxt(strOptions.substr(nPos, nPos2 - nPos + 3)); + if (vrwArgContext.RemoveArg(strQuotedTxt)) + { + m_bFound = true; +Index: tools/lldb-mi/MICmdArgValThreadGrp.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValThreadGrp.cpp (revision 224200) ++++ tools/lldb-mi/MICmdArgValThreadGrp.cpp (working copy) +@@ -133,7 +133,7 @@ + if (nPos != 0) + return false; + +- const CMIUtilString strNum = vrTxt.substr(1).c_str(); ++ const CMIUtilString strNum(vrTxt.substr(1)); + if (!strNum.IsNumber()) + return false; + +@@ -151,7 +151,7 @@ + bool + CMICmdArgValThreadGrp::ExtractNumber(const CMIUtilString &vrTxt) + { +- const CMIUtilString strNum = vrTxt.substr(1).c_str(); ++ const CMIUtilString strNum(vrTxt.substr(1)); + MIint64 nNumber = 0; + bool bOk = strNum.ExtractNumber(nNumber); + if (bOk) +Index: tools/lldb-mi/MICmdCmdSupportInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdSupportInfo.cpp (revision 224200) ++++ tools/lldb-mi/MICmdCmdSupportInfo.cpp (working copy) +@@ -89,7 +89,7 @@ + const MIuint nLen = rCmdToQuery.length(); + const CMICmdFactory &rCmdFactory = CMICmdFactory::Instance(); + if ((nLen > 1) && (rCmdToQuery[0] == '-')) +- m_bCmdFound = rCmdFactory.CmdExist(rCmdToQuery.substr(1, nLen - 1).c_str()); ++ m_bCmdFound = rCmdFactory.CmdExist(rCmdToQuery.substr(1, nLen - 1)); + else + m_bCmdFound = rCmdFactory.CmdExist(rCmdToQuery); + +Index: tools/lldb-mi/MICmdInterpreter.cpp +=================================================================== +--- tools/lldb-mi/MICmdInterpreter.cpp (revision 224200) ++++ tools/lldb-mi/MICmdInterpreter.cpp (working copy) +@@ -175,7 +175,7 @@ + if (!CMIUtilString(strNum.c_str()).IsNumber()) + return false; + +- m_miCmdData.strMiCmdToken = strNum.c_str(); ++ m_miCmdData.strMiCmdToken = strNum; + } + + m_miCmdData.bMIOldStyle = false; +@@ -210,7 +210,7 @@ + return false; + + const std::string strNum = vTextLine.substr(0, i); +- m_miCmdData.strMiCmdToken = strNum.c_str(); ++ m_miCmdData.strMiCmdToken = strNum; + m_miCmdData.bMIOldStyle = true; + + return true; +@@ -268,20 +268,20 @@ + { + if (nPos2 == nLen) + return false; +- const CMIUtilString cmd = CMIUtilString(vTextLine.substr(nPos + 1, nPos2 - nPos - 1).c_str()); ++ const CMIUtilString cmd(vTextLine.substr(nPos + 1, nPos2 - nPos - 1)); + if (cmd.empty()) + return false; + + m_miCmdData.strMiCmd = cmd; + + if (nPos2 < nLen) +- m_miCmdData.strMiCmdOption = CMIUtilString(vTextLine.substr(nPos2 + 1, nLen - nPos2 - 1).c_str()); ++ m_miCmdData.strMiCmdOption = vTextLine.substr(nPos2 + 1, nLen - nPos2 - 1); + + bFoundCmd = true; + } + else + { +- const CMIUtilString cmd = CMIUtilString(vTextLine.substr(nPos + 1, nLen - nPos - 1).c_str()); ++ const CMIUtilString cmd = vTextLine.substr(nPos + 1, nLen - nPos - 1); + if (cmd.empty()) + return false; + m_miCmdData.strMiCmd = cmd; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 224200) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -886,7 +886,8 @@ + const CMICmnMIValueConst miValueConst(utilValue.GetName()); + const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMIUtilString strContent(miValueList.ExtractContentNoBrackets()); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", strContent.c_str())); + const CMICmnMIValueResult miValueResult2("value", miValueConst2); + miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); +@@ -992,7 +993,8 @@ + const CMICmnMIValueConst miValueConst(utilValue.GetName()); + const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMIUtilString strContent(miValueList.ExtractContentNoBrackets()); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", strContent.c_str())); + const CMICmnMIValueResult miValueResult2("value", miValueConst2); + miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); +Index: tools/lldb-mi/MICmnLog.cpp +=================================================================== +--- tools/lldb-mi/MICmnLog.cpp (revision 224200) ++++ tools/lldb-mi/MICmnLog.cpp (working copy) +@@ -80,9 +80,12 @@ + const CMIUtilString &rCR(rFileLog.GetLineReturn()); + CMIUtilDateTimeStd date; + CMIUtilString msg; +- msg = CMIUtilString::Format("%s\n", CMIDriverMgr::Instance().GetAppVersion().c_str()); ++ const CMIUtilString strAppVersion(CMIDriverMgr::Instance().GetAppVersion()); ++ msg = CMIUtilString::Format("%s\n", strAppVersion.c_str()); + CMIUtilString logHdr(msg); +- msg = CMIUtilString::Format(MIRSRC(IDS_LOG_MSG_CREATION_DATE), date.GetDate().c_str(), date.GetTime().c_str(), rCR.c_str()); ++ const CMIUtilString strDate(date.GetDate()); ++ const CMIUtilString strTime(date.GetTime()); ++ msg = CMIUtilString::Format(MIRSRC(IDS_LOG_MSG_CREATION_DATE), strDate.c_str(), strTime.c_str(), rCR.c_str()); + logHdr += msg; + msg = CMIUtilString::Format(MIRSRC(IDS_LOG_MSG_FILE_LOGGER_PATH), rFileLog.GetFileNamePath().c_str(), rCR.c_str()); + logHdr += msg; +Index: tools/lldb-mi/MICmnLogMediumFile.cpp +=================================================================== +--- tools/lldb-mi/MICmnLogMediumFile.cpp (revision 224200) ++++ tools/lldb-mi/MICmnLogMediumFile.cpp (working copy) +@@ -292,7 +292,8 @@ + const CMIUtilString strCr("\n"); + CMIUtilString data; + const MIchar verbosityCode(ConvertLogVerbosityTypeToId(veType)); +- const CMIUtilString dt(CMIUtilString::Format("%s %s", m_strDate.c_str(), m_dateTime.GetTime().c_str())); ++ const CMIUtilString strTime(m_dateTime.GetTime()); ++ const CMIUtilString dt(CMIUtilString::Format("%s %s", m_strDate.c_str(), strTime.c_str())); + + data = CMIUtilString::Format("%c,%s,%s", verbosityCode, dt.c_str(), vData.c_str()); + data = ConvertCr(data); +Index: tools/lldb-mi/MIDriverMgr.cpp +=================================================================== +--- tools/lldb-mi/MIDriverMgr.cpp (revision 224200) ++++ tools/lldb-mi/MIDriverMgr.cpp (working copy) +@@ -223,8 +223,9 @@ + return MIstatus::failure; + if (!pDriver->DoInitialize()) + { ++ const CMIUtilString strDriverError(pDriver->GetError()); + SetErrorDescriptionn(MIRSRC(IDS_DRIVERMGR_DRIVER_ERR_INIT), pDriver->GetName().c_str(), vrDriverID.c_str(), +- pDriver->GetError().c_str()); ++ strDriverError.c_str()); + return MIstatus::failure; + } + +@@ -343,7 +344,8 @@ + { + if (!m_pDriverCurrent->DoMainLoop()) + { +- const CMIUtilString errMsg(CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_MAINLOOP), m_pDriverCurrent->GetError().c_str())); ++ const CMIUtilString strDriverCurrentError(m_pDriverCurrent->GetError()); ++ const CMIUtilString errMsg(CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_MAINLOOP), strDriverCurrentError.c_str())); + CMICmnStreamStdout::Instance().Write(errMsg, true); + return MIstatus::failure; + } +Index: tools/lldb-mi/MIUtilFileStd.cpp +=================================================================== +--- tools/lldb-mi/MIUtilFileStd.cpp (revision 224200) ++++ tools/lldb-mi/MIUtilFileStd.cpp (working copy) +@@ -276,7 +276,7 @@ + if (nPos > nPos2) + nPos2 = nPos; + +- const CMIUtilString strPath(vDirectoryPath.substr(0, nPos2).c_str()); ++ const CMIUtilString strPath(vDirectoryPath.substr(0, nPos2)); + return strPath; + } + +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 224200) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -66,6 +66,18 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: CMIUtilString constructor. ++// Type: Method. ++// Args: vpData - Reference to std::string data. ++// Return: None. ++// Throws: None. ++//-- ++CMIUtilString::CMIUtilString(const std::string &vrData) ++ : std::string(vrData) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: CMIUtilString assigment operator. + // Type: Method. + // Args: vpRhs - Pointer to UTF8 text data. +@@ -376,7 +388,7 @@ + if (nPos == (MIint)std::string::npos) + return *this; + +- const CMIUtilString strNew(substr(0, nPos).c_str()); ++ const CMIUtilString strNew(substr(0, nPos)); + + return strNew; + } +@@ -560,12 +572,12 @@ + const MIint nPos = find_last_not_of(pWhiteSpace); + if (nPos != (MIint)std::string::npos) + { +- strNew = substr(0, nPos + 1).c_str(); ++ strNew = substr(0, nPos + 1); + } + const MIint nPos2 = strNew.find_first_not_of(pWhiteSpace); + if (nPos2 != (MIint)std::string::npos) + { +- strNew = strNew.substr(nPos2).c_str(); ++ strNew = strNew.substr(nPos2); + } + + return strNew; +@@ -586,7 +598,7 @@ + if (nLen > 1) + { + if ((strNew[0] == vChar) && (strNew[nLen - 1] == vChar)) +- strNew = strNew.substr(1, nLen - 2).c_str(); ++ strNew = strNew.substr(1, nLen - 2); + } + + return strNew; +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 224200) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -54,6 +54,7 @@ + /* ctor */ CMIUtilString(void); + /* ctor */ CMIUtilString(const MIchar *vpData); + /* ctor */ CMIUtilString(const MIchar *const *vpData); ++ /* ctor */ CMIUtilString(const std::string &vrData); + // + bool ExtractNumber(MIint64 &vwrNumber) const; + CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const; Index: patches/lldbmi_fix_c_str_in_mirsrc_bug.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_c_str_in_mirsrc_bug.patch @@ -0,0 +1,125 @@ +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 224200) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -42,7 +42,7 @@ + {IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN, "File Handler. Unknown error opening '%s'"}, + {IDE_UTIL_FILE_ERR_WRITING_FILE, "File Handler. Error %s writing '%s'"}, + {IDE_UTIL_FILE_ERR_WRITING_NOTOPEN, "File Handler. File '%s' not open for write"}, +- {IDS_RESOURCES_ERR_STRING_NOT_FOUND, "Resources. String (%d) not found in resources"}, ++ {IDS_RESOURCES_ERR_STRING_NOT_FOUND, "Resources. String not found in resources"}, + {IDS_RESOURCES_ERR_STRING_TABLE_INVALID, "Resources. String resource table is not set up"}, + {IDS_MI_CLIENT_MSG, "Client message: \"%s\""}, + {IDS_LOG_MSG_CREATION_DATE, "Creation date %s time %s%s"}, +@@ -363,15 +363,15 @@ + // Return: CMIUtilString - Resource text. + // Throws: None. + //-- +-CMIUtilString +-CMICmnResources::GetString(const MIuint vResourceId) const ++const MIchar * ++CMICmnResources::GetCString(const MIuint vResourceId) const + { +- CMIUtilString str; +- const bool bFound = GetStringFromResource(vResourceId, str); ++ const MIchar *cStr(nullptr); ++ const bool bFound = GetStringFromResource(vResourceId, cStr); + MIunused(bFound); + assert(bFound); + +- return str; ++ return cStr; + } + + //++ ------------------------------------------------------------------------------------ +@@ -385,8 +385,8 @@ + bool + CMICmnResources::HasString(const MIuint vResourceId) const + { +- CMIUtilString str; +- return GetStringFromResource(vResourceId, str); ++ const MIchar *cStr(nullptr); ++ return GetStringFromResource(vResourceId, cStr); + } + + //++ ------------------------------------------------------------------------------------ +@@ -394,14 +394,14 @@ + // cannot be found and error is given returning the ID of the resource that + // cannot be located. + // Type: Method. +-// Args: vResourceId - (R) MI resource ID. +-// vrwResourceString - (W) Text. ++// Args: vResourceId - (R) MI resource ID. ++// vprwResourceCString - (W) Text. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool +-CMICmnResources::GetStringFromResource(const MIuint vResourceId, CMIUtilString &vrwResourceString) const ++CMICmnResources::GetStringFromResource(const MIuint vResourceId, const MIchar *&vprwResourceCString) const + { + MapRscrIdToTextData_t::const_iterator it = m_mapRscrIdToTextData.find(vResourceId); + if (it == m_mapRscrIdToTextData.end()) +@@ -413,14 +413,14 @@ + it = m_mapRscrIdToTextData.find(vResourceId); + if (it == m_mapRscrIdToTextData.end()) + { +- vrwResourceString = MIRSRC(IDS_RESOURCES_ERR_STRING_TABLE_INVALID); ++ vprwResourceCString = MIRSRC(IDS_RESOURCES_ERR_STRING_TABLE_INVALID); + return MIstatus::failure; + } + } + + if (it == m_mapRscrIdToTextData.end()) + { +- vrwResourceString = CMIUtilString::Format(MIRSRC(IDS_RESOURCES_ERR_STRING_NOT_FOUND), vResourceId); ++ vprwResourceCString = MIRSRC(IDS_RESOURCES_ERR_STRING_NOT_FOUND); + return MIstatus::failure; + } + } +@@ -430,7 +430,7 @@ + const MIchar *pRsrcData((*it).second); + + // Return result +- vrwResourceString = pRsrcData; ++ vprwResourceCString = pRsrcData; + + return MIstatus::success; + } +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 224200) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -297,13 +297,13 @@ + bool Initialize(void); + bool Shutdown(void); + +- CMIUtilString GetString(const MIuint vResourceId) const; ++ const MIchar *GetCString(const MIuint vResourceId) const; + bool HasString(const MIuint vResourceId) const; + + // Typedef: + private: +- typedef std::map MapRscrIdToTextData_t; +- typedef std::pair MapPairRscrIdToTextData_t; ++ typedef std::map MapRscrIdToTextData_t; ++ typedef std::pair MapPairRscrIdToTextData_t; + + // Enumerations: + private: +@@ -326,7 +326,7 @@ + /* ctor */ CMICmnResources(const CMICmnResources &); + void operator=(const CMICmnResources &); + +- bool GetStringFromResource(const MIuint vResourceId, CMIUtilString &vrwResourceString) const; ++ bool GetStringFromResource(const MIuint vResourceId, const MIchar *&vprwResourceCString) const; + bool ReadResourceStringData(void); + + // Overridden: +@@ -345,4 +345,4 @@ + //++ ========================================================================= + // Details: Macro short cut for retrieving a text data resource + //-- +-#define MIRSRC(x) CMICmnResources::Instance().GetString(x).c_str() ++#define MIRSRC(x) CMICmnResources::Instance().GetCString(x) Index: patches/lldbmi_fix_data_commands.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_data_commands.patch @@ -0,0 +1,320 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 228304) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -10,7 +10,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-disassemble doesn't show 'size' field") + def test_lldbmi_data_disassemble(self): + """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" + +@@ -38,7 +37,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-list-register-names doesn't work properly") + def test_lldbmi_data_list_register_names(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" + +@@ -65,7 +63,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-list-register-values doesn't work properly") + def test_lldbmi_data_list_register_values(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-values.""" + +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 228304) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -427,6 +427,7 @@ + lldb::addr_t addrOffSet = address.GetOffset(); + const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; ++ const size_t instrtSize = instrt.GetByteSize(); + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08llx", addr)); +@@ -438,9 +439,12 @@ + const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%lld", addrOffSet)); + const CMICmnMIValueResult miValueResult3("offset", miValueConst3); + miValueTuple.Add(miValueResult3); +- const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%s %s", pStrMnemonic, pStrOperands)); +- const CMICmnMIValueResult miValueResult4("inst", miValueConst4); ++ const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", instrtSize)); ++ const CMICmnMIValueResult miValueResult4("size", miValueConst4); + miValueTuple.Add(miValueResult4); ++ const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s", pStrMnemonic, pStrOperands)); ++ const CMICmnMIValueResult miValueResult5("inst", miValueConst5); ++ miValueTuple.Add(miValueResult5); + + if (nDisasmMode == 1) + { +@@ -826,6 +830,8 @@ + bool + CMICmdCmdDataListRegisterNames::Execute(void) + { ++ CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo); ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + if (!sbProcess.IsValid()) +@@ -834,24 +840,50 @@ + return MIstatus::failure; + } + +- lldb::SBThread thread = sbProcess.GetSelectedThread(); +- lldb::SBFrame frame = thread.GetSelectedFrame(); +- lldb::SBValueList registers = frame.GetRegisters(); +- const MIuint nRegisters = registers.GetSize(); +- for (MIuint i = 0; i < nRegisters; i++) ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); ++ if (!rVecRegNo.empty()) + { +- lldb::SBValue value = registers.GetValueAtIndex(i); +- const MIuint nRegChildren = value.GetNumChildren(); +- for (MIuint j = 0; j < nRegChildren; j++) ++ // List of required registers ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); ++ while (it != rVecRegNo.end()) + { +- lldb::SBValue value2 = value.GetChildAtIndex(j); +- if (value2.IsValid()) ++ const CMICmdArgValNumber *pRegNo = static_cast(*it); ++ const MIuint nRegIndex = pRegNo->GetValue(); ++ lldb::SBValue regValue = GetRegister(nRegIndex); ++ if (regValue.IsValid()) + { +- const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(value2).GetName()); ++ const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName()); + m_miValueList.Add(miValueConst); + } ++ ++ // Next ++ ++it; + } + } ++ else ++ { ++ // List of all registers ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ for (MIuint i = 0; i < nRegisters; i++) ++ { ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); ++ for (MIuint j = 0; j < nRegChildren; j++) ++ { ++ lldb::SBValue regValue = value.GetChildAtIndex(j); ++ if (regValue.IsValid()) ++ { ++ const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName()); ++ const bool bOk = m_miValueList.Add(miValueConst); ++ if (!bOk) ++ return MIstatus::failure; ++ } ++ } ++ } ++ } + + return MIstatus::success; + } +@@ -889,6 +921,42 @@ + return new CMICmdCmdDataListRegisterNames(); + } + ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBValue - LLDB SBValue object. ++// Throws: None. ++//-- ++lldb::SBValue ++CMICmdCmdDataListRegisterNames::GetRegister(const MIuint vRegisterIndex) const ++{ ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegisterIndex(vRegisterIndex); ++ for (MIuint i = 0; i < nRegisters; i++) ++ { ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); ++ if (nRegisterIndex >= nRegChildren) ++ { ++ nRegisterIndex -= nRegChildren; ++ continue; ++ } ++ ++ lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex); ++ if (value2.IsValid()) ++ { ++ return value2; ++ } ++ } ++ ++ return lldb::SBValue(); ++} ++ + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- +@@ -982,15 +1050,22 @@ + } + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); +- if (!rVecRegNo.empty ()) ++ if (!rVecRegNo.empty()) + { ++ // List of required registers + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +- while (it != rVecRegNo.end ()) ++ while (it != rVecRegNo.end()) + { + const CMICmdArgValNumber *pRegNo = static_cast(*it); +- const MIuint nReg = pRegNo->GetValue (); +- lldb::SBValue regValue = GetRegister (nReg); +- AddToOutput (regValue, nReg, eFormat); ++ const MIuint nRegIndex = pRegNo->GetValue(); ++ lldb::SBValue regValue = GetRegister(nRegIndex); ++ if (regValue.IsValid()) ++ { ++ const bool bOk = AddToOutput(nRegIndex, regValue, eFormat); ++ if (!bOk) ++ return MIstatus::failure; ++ } ++ + // Next + ++it; + } +@@ -998,23 +1073,27 @@ + else + { + // No register numbers are provided. Output all registers. +- lldb::SBThread thread = sbProcess.GetSelectedThread (); +- lldb::SBFrame frame = thread.GetSelectedFrame (); +- lldb::SBValueList registers = frame.GetRegisters (); +- const MIuint nRegisters = registers.GetSize (); +- MIuint index = 0; ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegIndex = 0; + for (MIuint i = 0; i < nRegisters; i++) + { +- lldb::SBValue value = registers.GetValueAtIndex (i); +- const MIuint nRegChildren = value.GetNumChildren (); ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); + for (MIuint j = 0; j < nRegChildren; j++) + { +- lldb::SBValue reg_value = value.GetChildAtIndex (j); +- if (reg_value.IsValid ()) ++ lldb::SBValue regValue = value.GetChildAtIndex(j); ++ if (regValue.IsValid()) + { +- AddToOutput (reg_value, index, eFormat); +- index++; ++ const bool bOk = AddToOutput(nRegIndex, regValue, eFormat); ++ if (!bOk) ++ return MIstatus::failure; + } ++ ++ // Next ++ ++nRegIndex; + } + } + } +@@ -1070,18 +1149,22 @@ + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegisterIndex(vRegisterIndex); + for (MIuint i = 0; i < nRegisters; i++) + { + lldb::SBValue value = registers.GetValueAtIndex(i); + const MIuint nRegChildren = value.GetNumChildren(); +- if (nRegChildren > 0) ++ if (nRegisterIndex >= nRegChildren) + { +- lldb::SBValue value2 = value.GetChildAtIndex(vRegisterIndex); +- if (value2.IsValid()) +- { +- return value2; +- } ++ nRegisterIndex -= nRegChildren; ++ continue; + } ++ ++ lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex); ++ if (value2.IsValid()) ++ { ++ return value2; ++ } + } + + return lldb::SBValue(); +@@ -1094,19 +1177,18 @@ + // Return: None + // Throws: None. + //-- +-void +-CMICmdCmdDataListRegisterValues::AddToOutput (const lldb::SBValue& value, MIuint index, +- CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat) ++bool ++CMICmdCmdDataListRegisterValues::AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue, ++ CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat) + { +- const CMICmnMIValueConst miValueConst (CMIUtilString::Format ("%u", index)); +- const CMICmnMIValueResult miValueResult ("number", miValueConst); +- const CMIUtilString strRegValue (CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted (value, eFormat)); +- const CMICmnMIValueConst miValueConst2 (strRegValue); +- const CMICmnMIValueResult miValueResult2 ("value", miValueConst2); +- +- CMICmnMIValueTuple miValueTuple (miValueResult); +- miValueTuple.Add (miValueResult2); +- m_miValueList.Add (miValueTuple); ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%u", vnIndex)); ++ const CMICmnMIValueResult miValueResult("number", miValueConst); ++ CMICmnMIValueTuple miValueTuple(miValueResult); ++ const CMIUtilString strRegValue(CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(vrValue, veVarFormat)); ++ const CMICmnMIValueConst miValueConst2(strRegValue); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ bool bOk = miValueTuple.Add(miValueResult2); ++ return bOk && m_miValueList.Add(miValueTuple); + } + + //--------------------------------------------------------------------------------------- +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 228304) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -219,6 +219,10 @@ + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataListRegisterNames(void); + ++ // Methods: ++ private: ++ lldb::SBValue GetRegister(const MIuint vRegisterIndex) const; ++ + // Attributes: + private: + const CMIUtilString m_constStrArgThreadGroup; // Not specified in MI spec but Eclipse gives this option +@@ -256,7 +260,7 @@ + // Methods: + private: + lldb::SBValue GetRegister(const MIuint vRegisterIndex) const; +- void AddToOutput (const lldb::SBValue& value, MIuint index, CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat); ++ bool AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue, CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat); + + // Attributes: + private: Index: patches/lldbmi_fix_data_commands.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_data_commands.v2.patch @@ -0,0 +1,2080 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 228304) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -1,94 +1,91 @@ + """ + Test that the lldb-mi driver works with -data-xxx commands + """ + + import lldbmi_testcase + from lldbtest import * + import unittest2 + + class MiDataTestCase(lldbmi_testcase.MiTestCaseBase): + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-disassemble doesn't show 'size' field") + def test_lldbmi_data_disassemble(self): + """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Get an address for disassembling: use main + self.runCmd("-data-evaluate-expression main") + self.expect("\^done,value=\"0x[0-9a-f]+\"") + addr = int(self.child.after.split("\"")[1], 16) + + # Test -data-disassemble: try to disassemble some address + self.runCmd("-data-disassemble -s %#x -e %#x -- 0" % (addr, addr + 0x10)) + self.expect("\^done,asm_insns=\[{address=\"%#x\",func-name=\"main\",offset=\"0x0\",size=\"[1-9]\",inst=\".+\"}," % addr) + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-list-register-names doesn't work properly") + def test_lldbmi_data_list_register_names(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -data-list-register-names: try to get all registers + self.runCmd("-data-list-register-names") + self.expect("\^done,register-names=\[\".+\",") + + # Test -data-list-register-names: try to get specified registers + self.runCmd("-data-list-register-names 0") + self.expect("\^done,register-names=\[\".+\"\]") + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-data-list-register-values doesn't work properly") + def test_lldbmi_data_list_register_values(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-values.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -data-list-register-values: try to get all registers + self.runCmd("-data-list-register-values x") + self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"") + + # Test -data-list-register-values: try to get specified registers + self.runCmd("-data-list-register-values x 0") + self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"}\]") + + if __name__ == '__main__': + unittest2.main() +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 228304) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -1,1463 +1,1545 @@ + //===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file is distributed under the University of Illinois Open Source + // License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + + //++ + // File: MICmdCmdData.cpp + // + // Overview: CMICmdCmdDataEvaluateExpression implementation. + // CMICmdCmdDataDisassemble implementation. + // CMICmdCmdDataReadMemoryBytes implementation. + // CMICmdCmdDataReadMemory implementation. + // CMICmdCmdDataListRegisterNames implementation. + // CMICmdCmdDataListRegisterValues implementation. + // CMICmdCmdDataListRegisterChanged implementation. + // CMICmdCmdDataWriteMemoryBytes implementation. + // CMICmdCmdDataWriteMemory implementation. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 + // Libraries: See MIReadmetxt. + // + // Copyright: None. + //-- + + // Third Party Headers: + #include "lldb/API/SBThread.h" + #include "lldb/API/SBInstruction.h" + #include "lldb/API/SBInstructionList.h" + #include "lldb/API/SBStream.h" + + // In-house headers: + #include "MICmdCmdData.h" + #include "MICmnMIResultRecord.h" + #include "MICmnMIValueConst.h" + #include "MICmnLLDBDebugger.h" + #include "MICmnLLDBDebugSessionInfo.h" + #include "MICmnLLDBProxySBValue.h" + #include "MICmdArgValNumber.h" + #include "MICmdArgValString.h" + #include "MICmdArgValThreadGrp.h" + #include "MICmdArgValOptionLong.h" + #include "MICmdArgValOptionShort.h" + #include "MICmdArgValListOfN.h" + #include "MICmdArgValConsume.h" + #include "MICmnLLDBDebugSessionInfoVarObj.h" + #include "MICmnLLDBUtilSBValue.h" + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataEvaluateExpression constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataEvaluateExpression::CMICmdCmdDataEvaluateExpression(void) + : m_bExpressionValid(true) + , m_bEvaluatedExpression(true) + , m_strValue("??") + , m_bCompositeVarType(false) + , m_bFoundInvalidChar(false) + , m_cExpressionInvalidChar(0x00) + , m_constStrArgThread("thread") + , m_constStrArgFrame("frame") + , m_constStrArgExpr("expr") + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-evaluate-expression"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataEvaluateExpression::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataEvaluateExpression destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataEvaluateExpression::~CMICmdCmdDataEvaluateExpression(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataEvaluateExpression::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgExpr, true, true, true, true))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataEvaluateExpression::Execute(void) + { + CMICMDBASE_GETOPTION(pArgExpr, String, m_constStrArgExpr); + + const CMIUtilString &rExpression(pArgExpr->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = sbProcess.GetSelectedThread(); + m_bExpressionValid = (thread.GetNumFrames() > 0); + if (!m_bExpressionValid) + return MIstatus::success; + + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValue value = frame.EvaluateExpression(rExpression.c_str()); + if (!value.IsValid()) + value = frame.FindVariable(rExpression.c_str()); + if (!value.IsValid()) + { + m_bEvaluatedExpression = false; + return MIstatus::success; + } + const CMICmnLLDBUtilSBValue utilValue(value); + if (!utilValue.HasName()) + { + if (HaveInvalidCharacterInExpression(rExpression, m_cExpressionInvalidChar)) + { + m_bFoundInvalidChar = true; + return MIstatus::success; + } + + m_strValue = rExpression; + return MIstatus::success; + } + if (rExpression.IsQuoted()) + { + m_strValue = rExpression.Trim('\"'); + return MIstatus::success; + } + + MIuint64 nNumber = 0; + if (CMICmnLLDBProxySBValue::GetValueAsUnsigned(value, nNumber) == MIstatus::success) + { + const lldb::ValueType eValueType = value.GetValueType(); + MIunused(eValueType); + m_strValue = utilValue.GetValue(); + CMIUtilString strCString; + if (CMICmnLLDBProxySBValue::GetCString(value, strCString)) + { + m_strValue += CMIUtilString::Format(" '%s'", strCString.c_str()); + } + return MIstatus::success; + } + + // Composite type i.e. struct + m_bCompositeVarType = true; + const MIuint nChild = value.GetNumChildren(); + for (MIuint i = 0; i < nChild; i++) + { + lldb::SBValue member = value.GetChildAtIndex(i); + const bool bValid = member.IsValid(); + CMIUtilString strType(MIRSRC(IDS_WORD_UNKNOWNTYPE_BRKTS)); + if (bValid) + { + const CMIUtilString strValue( + CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(member, CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural)); + const char *pTypeName = member.GetName(); + if (pTypeName != nullptr) + strType = pTypeName; + + // MI print "{variable = 1, variable2 = 3, variable3 = 5}" + const bool bNoQuotes = true; + const CMICmnMIValueConst miValueConst(strValue, bNoQuotes); + const bool bUseSpaces = true; + const CMICmnMIValueResult miValueResult(strType, miValueConst, bUseSpaces); + m_miValueTuple.Add(miValueResult, bUseSpaces); + } + } + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataEvaluateExpression::Acknowledge(void) + { + if (m_bExpressionValid) + { + if (m_bEvaluatedExpression) + { + if (m_bCompositeVarType) + { + const CMICmnMIValueConst miValueConst(m_miValueTuple.GetString()); + const CMICmnMIValueResult miValueResult("value", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + return MIstatus::success; + } + + if (m_bFoundInvalidChar) + { + const CMICmnMIValueConst miValueConst( + CMIUtilString::Format("Invalid character '%c' in expression", m_cExpressionInvalidChar)); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + return MIstatus::success; + } + + const CMICmnMIValueConst miValueConst(m_strValue); + const CMICmnMIValueResult miValueResult("value", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + return MIstatus::success; + } + + const CMICmnMIValueConst miValueConst("Could not evaluate expression"); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + return MIstatus::success; + } + + const CMICmnMIValueConst miValueConst("Invalid expression"); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataEvaluateExpression::CreateSelf(void) + { + return new CMICmdCmdDataEvaluateExpression(); + } + + //++ ------------------------------------------------------------------------------------ + // Details: Examine the expression string to see if it contains invalid characters. + // Type: Method. + // Args: vrExpr - (R) Expression string given to *this command. + // vrwInvalidChar - (W) True = Invalid character found, false = nothing found. + // Return: bool - True = Invalid character found, false = nothing found. + // Throws: None. + //-- + bool + CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, MIchar &vrwInvalidChar) + { + bool bFoundInvalidCharInExpression = false; + vrwInvalidChar = 0x00; + + if (vrExpr.at(0) == '\\') + { + // Example: Mouse hover over "%5d" expression has \"%5d\" in it + bFoundInvalidCharInExpression = true; + vrwInvalidChar = '\\'; + } + + return bFoundInvalidCharInExpression; + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataDisassemble constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataDisassemble::CMICmdCmdDataDisassemble(void) + : m_constStrArgThread("thread") + , m_constStrArgAddrStart("s") + , m_constStrArgAddrEnd("e") + , m_constStrArgConsume("--") + , m_constStrArgMode("mode") + , m_miValueList(true) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-disassemble"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataDisassemble::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataDisassemble destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataDisassemble::~CMICmdCmdDataDisassemble(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataDisassemble::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrEnd, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValConsume(m_constStrArgConsume, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgMode, true, true))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataDisassemble::Execute(void) + { + CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread); + CMICMDBASE_GETOPTION(pArgAddrStart, OptionShort, m_constStrArgAddrStart); + CMICMDBASE_GETOPTION(pArgAddrEnd, OptionShort, m_constStrArgAddrEnd); + CMICMDBASE_GETOPTION(pArgMode, Number, m_constStrArgMode); + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; + if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } + CMIUtilString strAddrStart; + if (!pArgAddrStart->GetExpectedOption(strAddrStart)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(), + m_constStrArgAddrStart.c_str())); + return MIstatus::failure; + } + MIint64 nAddrStart = 0; + if (!strAddrStart.ExtractNumber(nAddrStart)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(), + m_constStrArgAddrStart.c_str())); + return MIstatus::failure; + } + + CMIUtilString strAddrEnd; + if (!pArgAddrEnd->GetExpectedOption(strAddrEnd)) + { + SetError( + CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str())); + return MIstatus::failure; + } + MIint64 nAddrEnd = 0; + if (!strAddrEnd.ExtractNumber(nAddrEnd)) + { + SetError( + CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str())); + return MIstatus::failure; + } + const MIuint nDisasmMode = pArgMode->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + lldb::addr_t lldbStartAddr = static_cast(nAddrStart); + lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart); + const MIuint nInstructions = instructions.GetSize(); + for (size_t i = 0; i < nInstructions; i++) + { + const MIchar *pUnknown = "??"; + lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i); + const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget); + pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown; + lldb::SBAddress address = instrt.GetAddress(); + lldb::addr_t addr = address.GetLoadAddress(sbTarget); + const MIchar *pFnName = address.GetFunction().GetName(); + pFnName = (pFnName != nullptr) ? pFnName : pUnknown; + lldb::addr_t addrOffSet = address.GetOffset(); + const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; ++ const size_t instrtSize = instrt.GetByteSize(); + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08llx", addr)); + const CMICmnMIValueResult miValueResult("address", miValueConst); + CMICmnMIValueTuple miValueTuple(miValueResult); + const CMICmnMIValueConst miValueConst2(pFnName); + const CMICmnMIValueResult miValueResult2("func-name", miValueConst2); + miValueTuple.Add(miValueResult2); + const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%lld", addrOffSet)); + const CMICmnMIValueResult miValueResult3("offset", miValueConst3); + miValueTuple.Add(miValueResult3); +- const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%s %s", pStrMnemonic, pStrOperands)); +- const CMICmnMIValueResult miValueResult4("inst", miValueConst4); ++ const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", instrtSize)); ++ const CMICmnMIValueResult miValueResult4("size", miValueConst4); + miValueTuple.Add(miValueResult4); ++ const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s", pStrMnemonic, pStrOperands)); ++ const CMICmnMIValueResult miValueResult5("inst", miValueConst5); ++ miValueTuple.Add(miValueResult5); + + if (nDisasmMode == 1) + { + lldb::SBLineEntry lineEntry = address.GetLineEntry(); + const MIuint nLine = lineEntry.GetLine(); + const MIchar *pFileName = lineEntry.GetFileSpec().GetFilename(); + pFileName = (pFileName != nullptr) ? pFileName : pUnknown; + + // MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}" + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%u", nLine)); + const CMICmnMIValueResult miValueResult("line", miValueConst); + CMICmnMIValueTuple miValueTuple2(miValueResult); + const CMICmnMIValueConst miValueConst2(pFileName); + const CMICmnMIValueResult miValueResult2("file", miValueConst2); + miValueTuple2.Add(miValueResult2); + const CMICmnMIValueList miValueList(miValueTuple); + const CMICmnMIValueResult miValueResult3("line_asm_insn", miValueList); + miValueTuple2.Add(miValueResult3); + const CMICmnMIValueResult miValueResult4("src_and_asm_line", miValueTuple2); + m_miValueList.Add(miValueResult4); + } + else + { + m_miValueList.Add(miValueTuple); + } + } + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataDisassemble::Acknowledge(void) + { + const CMICmnMIValueResult miValueResult("asm_insns", m_miValueList); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataDisassemble::CreateSelf(void) + { + return new CMICmdCmdDataDisassemble(); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataReadMemoryBytes constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes(void) + : m_constStrArgThread("thread") + , m_constStrArgByteOffset("o") + , m_constStrArgAddrStart("address") + , m_constStrArgNumBytes("count") + , m_pBufferMemory(nullptr) + , m_nAddrStart(0) + , m_nAddrNumBytesToRead(0) + , m_nAddrOffset(0) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-read-memory-bytes"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataReadMemoryBytes::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataReadMemoryBytes destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataReadMemoryBytes::~CMICmdCmdDataReadMemoryBytes(void) + { + if (m_pBufferMemory != nullptr) + { + delete[] m_pBufferMemory; + m_pBufferMemory = nullptr; + } + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataReadMemoryBytes::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = + bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataReadMemoryBytes::Execute(void) + { + CMICMDBASE_GETOPTION(pArgAddrStart, Number, m_constStrArgAddrStart); + CMICMDBASE_GETOPTION(pArgAddrOffset, Number, m_constStrArgByteOffset); + CMICMDBASE_GETOPTION(pArgNumBytes, Number, m_constStrArgNumBytes); + + const MIuint64 nAddrStart = pArgAddrStart->GetValue(); + const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue(); + if (pArgAddrOffset->GetFound()) + m_nAddrOffset = pArgAddrOffset->GetValue(); + + m_pBufferMemory = new MIuchar[nAddrNumBytes]; + if (m_pBufferMemory == nullptr) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), nAddrNumBytes)); + return MIstatus::failure; + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); + if (nReadBytes != nAddrNumBytes) + { + SetError( + CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart)); + return MIstatus::failure; + } + if (error.Fail()) + { + lldb::SBStream err; + const bool bOk = error.GetDescription(err); + MIunused(bOk); + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart, + err.GetData())); + return MIstatus::failure; + } + + m_nAddrStart = nAddrStart; + m_nAddrNumBytesToRead = nAddrNumBytes; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataReadMemoryBytes::Acknowledge(void) + { + // MI: memory=[{begin=\"0x%08x\",offset=\"0x%08x\",end=\"0x%08x\",contents=\" \" }]" + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08x", m_nAddrStart)); + const CMICmnMIValueResult miValueResult("begin", miValueConst); + CMICmnMIValueTuple miValueTuple(miValueResult); + const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08x", m_nAddrOffset)); + const CMICmnMIValueResult miValueResult2("offset", miValueConst2); + miValueTuple.Add(miValueResult2); + const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08x", m_nAddrStart + m_nAddrNumBytesToRead)); + const CMICmnMIValueResult miValueResult3("end", miValueConst3); + miValueTuple.Add(miValueResult3); + + // MI: contents=\" \" + CMIUtilString strContent; + strContent.reserve((m_nAddrNumBytesToRead << 1) + 1); + for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++) + { + strContent += CMIUtilString::Format("%02x", m_pBufferMemory[i]); + } + const CMICmnMIValueConst miValueConst4(strContent); + const CMICmnMIValueResult miValueResult4("contents", miValueConst4); + miValueTuple.Add(miValueResult4); + const CMICmnMIValueList miValueList(miValueTuple); + const CMICmnMIValueResult miValueResult5("memory", miValueList); + + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataReadMemoryBytes::CreateSelf(void) + { + return new CMICmdCmdDataReadMemoryBytes(); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataReadMemory constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataReadMemory::CMICmdCmdDataReadMemory(void) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-read-memory"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataReadMemory::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataReadMemory destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataReadMemory::~CMICmdCmdDataReadMemory(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataReadMemory::Execute(void) + { + // Do nothing - command deprecated use "data-read-memory-bytes" command + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataReadMemory::Acknowledge(void) + { + // Command CMICmdCmdSupportListFeatures sends "data-read-memory-bytes" which causes this command not to be called + const CMICmnMIValueConst miValueConst(MIRSRC(IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED)); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataReadMemory::CreateSelf(void) + { + return new CMICmdCmdDataReadMemory(); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataListRegisterNames constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterNames::CMICmdCmdDataListRegisterNames(void) + : m_constStrArgThreadGroup("thread-group") + , m_constStrArgRegNo("regno") + , m_miValueList(true) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-names"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataListRegisterNames::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataReadMemoryBytes destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterNames::~CMICmdCmdDataListRegisterNames(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterNames::ParseArgs(void) + { + bool bOk = m_setCmdArgs.Add( + *(new CMICmdArgValOptionLong(m_constStrArgThreadGroup, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValListOfN(m_constStrArgRegNo, false, false, CMICmdArgValListBase::eArgValType_Number))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterNames::Execute(void) + { ++ CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo); ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + +- lldb::SBThread thread = sbProcess.GetSelectedThread(); +- lldb::SBFrame frame = thread.GetSelectedFrame(); +- lldb::SBValueList registers = frame.GetRegisters(); +- const MIuint nRegisters = registers.GetSize(); +- for (MIuint i = 0; i < nRegisters; i++) ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); ++ if (!rVecRegNo.empty()) + { +- lldb::SBValue value = registers.GetValueAtIndex(i); +- const MIuint nRegChildren = value.GetNumChildren(); +- for (MIuint j = 0; j < nRegChildren; j++) ++ // List of required registers ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); ++ while (it != rVecRegNo.end()) + { +- lldb::SBValue value2 = value.GetChildAtIndex(j); +- if (value2.IsValid()) ++ const CMICmdArgValNumber *pRegNo = static_cast(*it); ++ const MIuint nRegIndex = pRegNo->GetValue(); ++ lldb::SBValue regValue = GetRegister(nRegIndex); ++ if (regValue.IsValid()) + { +- const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(value2).GetName()); ++ const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName()); + m_miValueList.Add(miValueConst); + } ++ ++ // Next ++ ++it; ++ } ++ } ++ else ++ { ++ // List of all registers ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ for (MIuint i = 0; i < nRegisters; i++) ++ { ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); ++ for (MIuint j = 0; j < nRegChildren; j++) ++ { ++ lldb::SBValue regValue = value.GetChildAtIndex(j); ++ if (regValue.IsValid()) ++ { ++ const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName()); ++ const bool bOk = m_miValueList.Add(miValueConst); ++ if (!bOk) ++ return MIstatus::failure; ++ } ++ } + } + } + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterNames::Acknowledge(void) + { + const CMICmnMIValueResult miValueResult("register-names", m_miValueList); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataListRegisterNames::CreateSelf(void) + { + return new CMICmdCmdDataListRegisterNames(); + } + ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBValue - LLDB SBValue object. ++// Throws: None. ++//-- ++lldb::SBValue ++CMICmdCmdDataListRegisterNames::GetRegister(const MIuint vRegisterIndex) const ++{ ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegisterIndex(vRegisterIndex); ++ for (MIuint i = 0; i < nRegisters; i++) ++ { ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); ++ if (nRegisterIndex >= nRegChildren) ++ { ++ nRegisterIndex -= nRegChildren; ++ continue; ++ } ++ ++ lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex); ++ if (value2.IsValid()) ++ { ++ return value2; ++ } ++ } ++ ++ return lldb::SBValue(); ++} ++ + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataListRegisterValues constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterValues::CMICmdCmdDataListRegisterValues(void) + : m_constStrArgThread("thread") + , m_constStrArgSkip("skip-unavailable") + , m_constStrArgFormat("fmt") + , m_constStrArgRegNo("regno") + , m_miValueList(true) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-values"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataListRegisterValues::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataListRegisterValues destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterValues::~CMICmdCmdDataListRegisterValues(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterValues::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSkip, false, false))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgFormat, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValListOfN(m_constStrArgRegNo, false, true, CMICmdArgValListBase::eArgValType_Number))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterValues::Execute(void) + { + CMICMDBASE_GETOPTION(pArgFormat, String, m_constStrArgFormat); + CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo); + + const CMIUtilString &rStrFormat(pArgFormat->GetValue()); + if (rStrFormat.length() != 1) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str())); + return MIstatus::failure; + } + const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat = CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(rStrFormat[0]); + if (eFormat == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str())); + return MIstatus::failure; + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); +- if (!rVecRegNo.empty ()) ++ if (!rVecRegNo.empty()) + { ++ // List of required registers + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +- while (it != rVecRegNo.end ()) ++ while (it != rVecRegNo.end()) + { + const CMICmdArgValNumber *pRegNo = static_cast(*it); +- const MIuint nReg = pRegNo->GetValue (); +- lldb::SBValue regValue = GetRegister (nReg); +- AddToOutput (regValue, nReg, eFormat); ++ const MIuint nRegIndex = pRegNo->GetValue(); ++ lldb::SBValue regValue = GetRegister(nRegIndex); ++ if (regValue.IsValid()) ++ { ++ const bool bOk = AddToOutput(nRegIndex, regValue, eFormat); ++ if (!bOk) ++ return MIstatus::failure; ++ } ++ + // Next + ++it; + } + } + else + { + // No register numbers are provided. Output all registers. +- lldb::SBThread thread = sbProcess.GetSelectedThread (); +- lldb::SBFrame frame = thread.GetSelectedFrame (); +- lldb::SBValueList registers = frame.GetRegisters (); +- const MIuint nRegisters = registers.GetSize (); +- MIuint index = 0; ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); ++ lldb::SBFrame frame = thread.GetSelectedFrame(); ++ lldb::SBValueList registers = frame.GetRegisters(); ++ const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegIndex = 0; + for (MIuint i = 0; i < nRegisters; i++) + { +- lldb::SBValue value = registers.GetValueAtIndex (i); +- const MIuint nRegChildren = value.GetNumChildren (); ++ lldb::SBValue value = registers.GetValueAtIndex(i); ++ const MIuint nRegChildren = value.GetNumChildren(); + for (MIuint j = 0; j < nRegChildren; j++) + { +- lldb::SBValue reg_value = value.GetChildAtIndex (j); +- if (reg_value.IsValid ()) ++ lldb::SBValue regValue = value.GetChildAtIndex(j); ++ if (regValue.IsValid()) + { +- AddToOutput (reg_value, index, eFormat); +- index++; ++ const bool bOk = AddToOutput(nRegIndex, regValue, eFormat); ++ if (!bOk) ++ return MIstatus::failure; + } ++ ++ // Next ++ ++nRegIndex; + } + } + } + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterValues::Acknowledge(void) + { + const CMICmnMIValueResult miValueResult("register-values", m_miValueList); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataListRegisterValues::CreateSelf(void) + { + return new CMICmdCmdDataListRegisterValues(); + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Method. + // Args: None. + // Return: lldb::SBValue - LLDB SBValue object. + // Throws: None. + //-- + lldb::SBValue + CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const + { + lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); ++ MIuint nRegisterIndex(vRegisterIndex); + for (MIuint i = 0; i < nRegisters; i++) + { + lldb::SBValue value = registers.GetValueAtIndex(i); + const MIuint nRegChildren = value.GetNumChildren(); +- if (nRegChildren > 0) ++ if (nRegisterIndex >= nRegChildren) + { +- lldb::SBValue value2 = value.GetChildAtIndex(vRegisterIndex); +- if (value2.IsValid()) +- { +- return value2; +- } ++ nRegisterIndex -= nRegChildren; ++ continue; ++ } ++ ++ lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex); ++ if (value2.IsValid()) ++ { ++ return value2; + } + } + + return lldb::SBValue(); + } + + //++ ------------------------------------------------------------------------------------ + // Details: Adds the register value to the output list. + // Type: Method. + // Args: Value of the register, its index and output format. + // Return: None + // Throws: None. + //-- +-void +-CMICmdCmdDataListRegisterValues::AddToOutput (const lldb::SBValue& value, MIuint index, +- CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat) +-{ +- const CMICmnMIValueConst miValueConst (CMIUtilString::Format ("%u", index)); +- const CMICmnMIValueResult miValueResult ("number", miValueConst); +- const CMIUtilString strRegValue (CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted (value, eFormat)); +- const CMICmnMIValueConst miValueConst2 (strRegValue); +- const CMICmnMIValueResult miValueResult2 ("value", miValueConst2); +- +- CMICmnMIValueTuple miValueTuple (miValueResult); +- miValueTuple.Add (miValueResult2); +- m_miValueList.Add (miValueTuple); ++bool ++CMICmdCmdDataListRegisterValues::AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue, ++ CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat) ++{ ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%u", vnIndex)); ++ const CMICmnMIValueResult miValueResult("number", miValueConst); ++ CMICmnMIValueTuple miValueTuple(miValueResult); ++ const CMIUtilString strRegValue(CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(vrValue, veVarFormat)); ++ const CMICmnMIValueConst miValueConst2(strRegValue); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ bool bOk = miValueTuple.Add(miValueResult2); ++ return bOk && m_miValueList.Add(miValueTuple); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataListRegisterChanged constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterChanged::CMICmdCmdDataListRegisterChanged(void) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-changed-registers"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataListRegisterChanged::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataListRegisterChanged destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataListRegisterChanged::~CMICmdCmdDataListRegisterChanged(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterChanged::Execute(void) + { + // Do nothing + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataListRegisterChanged::Acknowledge(void) + { + const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED)); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataListRegisterChanged::CreateSelf(void) + { + return new CMICmdCmdDataListRegisterChanged(); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataWriteMemoryBytes constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataWriteMemoryBytes::CMICmdCmdDataWriteMemoryBytes(void) + : m_constStrArgThread("thread") + , m_constStrArgAddr("address") + , m_constStrArgContents("contents") + , m_constStrArgCount("count") + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-write-memory-bytes"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataWriteMemoryBytes::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataWriteMemoryBytes destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataWriteMemoryBytes::~CMICmdCmdDataWriteMemoryBytes(void) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemoryBytes::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgAddr, true, true, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgContents, true, true, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgCount, false, true, false, true))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemoryBytes::Execute(void) + { + // Do nothing - not reproduceable (yet) in Eclipse + // CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset ); + // CMICMDBASE_GETOPTION( pArgAddr, String, m_constStrArgAddr ); + // CMICMDBASE_GETOPTION( pArgNumber, String, m_constStrArgNumber ); + // CMICMDBASE_GETOPTION( pArgContents, String, m_constStrArgContents ); + // + // Numbers extracts as string types as they could be hex numbers + // '&' is not recognised and so has to be removed + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemoryBytes::Acknowledge(void) + { + const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED)); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataWriteMemoryBytes::CreateSelf(void) + { + return new CMICmdCmdDataWriteMemoryBytes(); + } + + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + //--------------------------------------------------------------------------------------- + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataWriteMemory constructor. + // Type: Method. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataWriteMemory::CMICmdCmdDataWriteMemory(void) + : m_constStrArgThread("thread") + , m_constStrArgOffset("o") + , m_constStrArgAddr("address") + , m_constStrArgD("d") + , m_constStrArgNumber("a number") + , m_constStrArgContents("contents") + , m_nAddr(0) + , m_nCount(0) + , m_pBufferMemory(nullptr) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-write-memory"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdDataWriteMemory::CreateSelf; + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdCmdDataWriteMemory destructor. + // Type: Overrideable. + // Args: None. + // Return: None. + // Throws: None. + //-- + CMICmdCmdDataWriteMemory::~CMICmdCmdDataWriteMemory(void) + { + if (m_pBufferMemory != nullptr) + { + delete[] m_pBufferMemory; + m_pBufferMemory = nullptr; + } + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The parses the command line options + // arguments to extract values for each of those arguments. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemory::ParseArgs(void) + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddr, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgD, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, true, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgContents, true, true))); + return (bOk && ParseValidateCmdOptions()); + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command does work in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemory::Execute(void) + { + CMICMDBASE_GETOPTION(pArgOffset, OptionShort, m_constStrArgOffset); + CMICMDBASE_GETOPTION(pArgAddr, Number, m_constStrArgAddr); + CMICMDBASE_GETOPTION(pArgNumber, Number, m_constStrArgNumber); + CMICMDBASE_GETOPTION(pArgContents, Number, m_constStrArgContents); + + MIuint nAddrOffset = 0; + if (pArgOffset->GetFound() && !pArgOffset->GetExpectedOption(nAddrOffset)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddr.c_str())); + return MIstatus::failure; + } + m_nAddr = pArgAddr->GetValue(); + m_nCount = pArgNumber->GetValue(); + const MIuint64 nValue = pArgContents->GetValue(); + + m_pBufferMemory = new MIuchar[m_nCount]; + if (m_pBufferMemory == nullptr) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), m_nCount)); + return MIstatus::failure; + } + *m_pBufferMemory = static_cast(nValue); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + lldb::addr_t addr = static_cast(m_nAddr + nAddrOffset); + const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); + if (nBytesWritten != static_cast(m_nCount)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr)); + return MIstatus::failure; + } + if (error.Fail()) + { + lldb::SBStream err; + const bool bOk = error.GetDescription(err); + MIunused(bOk); + SetError( + CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES), m_cmdData.strMiCmd.c_str(), m_nCount, addr, err.GetData())); + return MIstatus::failure; + } + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result + // for the work carried out in the Execute(). + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmdCmdDataWriteMemory::Acknowledge(void) + { + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); + m_miResultRecord = miRecordResult; + + return MIstatus::success; + } + + //++ ------------------------------------------------------------------------------------ + // Details: Required by the CMICmdFactory when registering *this command. The factory + // calls this function to create an instance of *this command. + // Type: Static method. + // Args: None. + // Return: CMICmdBase * - Pointer to a new command. + // Throws: None. + //-- + CMICmdBase * + CMICmdCmdDataWriteMemory::CreateSelf(void) + { + return new CMICmdCmdDataWriteMemory(); + } +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 228304) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -1,373 +1,377 @@ + //===-- MICmdCmdData.h ------------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file is distributed under the University of Illinois Open Source + // License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + + //++ + // File: MICmdCmdData.h + // + // Overview: CMICmdCmdDataEvaluateExpression interface. + // CMICmdCmdDataDisassemble interface. + // CMICmdCmdDataReadMemoryBytes interface. + // CMICmdCmdDataReadMemory interface. + // CMICmdCmdDataListRegisterNames interface. + // CMICmdCmdDataListRegisterValues interface. + // CMICmdCmdDataListRegisterChanged interface. + // CMICmdCmdDataWriteMemoryBytes interface. + // CMICmdCmdDataWriteMemory interface. + // + // To implement new MI commands derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class + // to the command factory. The files of relevance are: + // MICmdCommands.cpp + // MICmdBase.h / .cpp + // MICmdCmd.h / .cpp + // For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery + // command class as an example. + // + // Environment: Compilers: Visual C++ 12. + // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 + // Libraries: See MIReadmetxt. + // + // Copyright: None. + //-- + + #pragma once + + // In-house headers: + #include "MICmdBase.h" + #include "MICmnMIValueTuple.h" + #include "MICmnMIValueList.h" + #include "MICmnLLDBDebugSessionInfoVarObj.h" + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-evaluate-expression". + // Gotchas: None. + // Authors: Illya Rudkin 26/03/2014. + // Changes: None. + //-- + class CMICmdCmdDataEvaluateExpression : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataEvaluateExpression(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataEvaluateExpression(void); + + // Methods: + private: + bool HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, MIchar &vrwInvalidChar); + + // Attributes: + private: + bool m_bExpressionValid; // True = yes is valid, false = not valid + bool m_bEvaluatedExpression; // True = yes is expression evaluated, false = failed + CMIUtilString m_strValue; + CMICmnMIValueTuple m_miValueTuple; + bool m_bCompositeVarType; // True = yes composite type, false = internal type + bool m_bFoundInvalidChar; // True = yes found unexpected character in the expression, false = all ok + MIchar m_cExpressionInvalidChar; + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgExpr; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-disassemble". + // Gotchas: None. + // Authors: Illya Rudkin 19/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataDisassemble : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataDisassemble(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataDisassemble(void); + + // Attributes: + private: + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgAddrStart; // MI spec non mandatory, *this command mandatory + const CMIUtilString m_constStrArgAddrEnd; // MI spec non mandatory, *this command mandatory + const CMIUtilString m_constStrArgConsume; + const CMIUtilString m_constStrArgMode; + CMICmnMIValueList m_miValueList; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-read-memory-bytes". + // Gotchas: None. + // Authors: Illya Rudkin 20/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataReadMemoryBytes : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataReadMemoryBytes(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataReadMemoryBytes(void); + + // Attributes: + private: + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgByteOffset; + const CMIUtilString m_constStrArgAddrStart; + const CMIUtilString m_constStrArgNumBytes; + MIuchar *m_pBufferMemory; + MIuint64 m_nAddrStart; + MIuint64 m_nAddrNumBytesToRead; + MIuint64 m_nAddrOffset; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-read-memory". + // Gotchas: None. + // Authors: Illya Rudkin 21/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataReadMemory : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataReadMemory(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataReadMemory(void); + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-list-register-names". + // Gotchas: None. + // Authors: Illya Rudkin 21/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataListRegisterNames : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataListRegisterNames(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataListRegisterNames(void); + ++ // Methods: ++ private: ++ lldb::SBValue GetRegister(const MIuint vRegisterIndex) const; ++ + // Attributes: + private: + const CMIUtilString m_constStrArgThreadGroup; // Not specified in MI spec but Eclipse gives this option + const CMIUtilString m_constStrArgRegNo; // Not handled by *this command + CMICmnMIValueList m_miValueList; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-list-register-values". + // Gotchas: None. + // Authors: Illya Rudkin 21/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataListRegisterValues : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataListRegisterValues(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataListRegisterValues(void); + + // Methods: + private: + lldb::SBValue GetRegister(const MIuint vRegisterIndex) const; +- void AddToOutput (const lldb::SBValue& value, MIuint index, CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat); ++ bool AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue, CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat); + + // Attributes: + private: + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option + const CMIUtilString m_constStrArgSkip; // Not handled by *this command + const CMIUtilString m_constStrArgFormat; + const CMIUtilString m_constStrArgRegNo; + CMICmnMIValueList m_miValueList; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-list-changed-registers". + // Gotchas: None. + // Authors: Illya Rudkin 22/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataListRegisterChanged : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataListRegisterChanged(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataListRegisterChanged(void); + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-read-memory-bytes". + // Gotchas: None. + // Authors: Illya Rudkin 30/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataWriteMemoryBytes : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataWriteMemoryBytes(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataWriteMemoryBytes(void); + + // Attributes: + private: + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgAddr; + const CMIUtilString m_constStrArgContents; + const CMIUtilString m_constStrArgCount; + CMIUtilString m_strContents; + }; + + //++ ============================================================================ + // Details: MI command class. MI commands derived from the command base class. + // *this class implements MI command "data-read-memory". + // Not specified in MI spec but Eclipse gives *this command. + // Gotchas: None. + // Authors: Illya Rudkin 02/05/2014. + // Changes: None. + //-- + class CMICmdCmdDataWriteMemory : public CMICmdBase + { + // Statics: + public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: + public: + /* ctor */ CMICmdCmdDataWriteMemory(void); + + // Overridden: + public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdDataWriteMemory(void); + + // Attributes: + private: + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command. + const CMIUtilString m_constStrArgOffset; // Not specified in MI spec but Eclipse gives this option. + const CMIUtilString m_constStrArgAddr; // Not specified in MI spec but Eclipse gives this option. + const CMIUtilString m_constStrArgD; // Not specified in MI spec but Eclipse gives this option. + const CMIUtilString m_constStrArgNumber; // Not specified in MI spec but Eclipse gives this option. + const CMIUtilString m_constStrArgContents; // Not specified in MI spec but Eclipse gives this option. + MIuint64 m_nAddr; + CMIUtilString m_strContents; + MIuint64 m_nCount; + MIuchar *m_pBufferMemory; + }; Index: patches/lldbmi_fix_data_read_memory_bytes_hex_format.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_data_read_memory_bytes_hex_format.patch @@ -0,0 +1,153 @@ +Index: tools/lldb-mi/MICmdArgValNumber.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.cpp (revision 228328) ++++ tools/lldb-mi/MICmdArgValNumber.cpp (working copy) +@@ -31,21 +31,25 @@ + // Throws: None. + //-- + CMICmdArgValNumber::CMICmdArgValNumber(void) +- : m_nNumber(0) ++ : m_nNumberFormatMask(CMICmdArgValNumber::eArgValNumberFormat_Decimal) ++ , m_nNumber(0) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdArgValNumber constructor. + // Type: Method. +-// Args: vrArgName - (R) Argument's name to search by. +-// vbMandatory - (R) True = Yes must be present, false = optional argument. +-// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// Args: vrArgName - (R) Argument's name to search by. ++// vbMandatory - (R) True = Yes must be present, false = optional argument. ++// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// vnNumberFormatMask - (R) ORing format mask of ArgValNumberFormat_e items. + // Return: None. + // Throws: None. + //-- +-CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd) ++CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask /* = CMICmdArgValNumber::eArgValNumberFormat_Decimal*/) + : CMICmdArgValBaseTemplate(vrArgName, vbMandatory, vbHandleByCmd) ++ , m_nNumberFormatMask(vnNumberFormatMask) + , m_nNumber(0) + { + } +@@ -128,11 +132,20 @@ + bool + CMICmdArgValNumber::IsArgNumber(const CMIUtilString &vrTxt) const + { ++ const bool bFormatDecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Decimal); ++ const bool bFormatHexadecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Hexadecimal); ++ + // Look for --someLongOption + if (std::string::npos != vrTxt.find("--")) + return false; + +- return vrTxt.IsNumber(); ++ if (bFormatDecimal && vrTxt.IsNumber()) ++ return true; ++ ++ if (bFormatHexadecimal && vrTxt.IsHexadecimalNumber()) ++ return true; ++ ++ return false; + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmdArgValNumber.h +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.h (revision 228328) ++++ tools/lldb-mi/MICmdArgValNumber.h (working copy) +@@ -40,10 +40,24 @@ + //-- + class CMICmdArgValNumber : public CMICmdArgValBaseTemplate + { ++ // Enums: ++ public: ++ //++ --------------------------------------------------------------------------------- ++ // Details: CMICmdArgValNumber needs to know what format of argument to look for in ++ // the command options text. ++ //-- ++ enum ArgValNumberFormat_e ++ { ++ eArgValNumberFormat_Decimal = (1u << 0), ++ eArgValNumberFormat_Hexadecimal = (1u << 1), ++ eArgValNumberFormat_Auto = ((eArgValNumberFormat_Hexadecimal << 1) - 1u) ///< Indicates to try and lookup everything up during a query. ++ }; ++ + // Methods: + public: + /* ctor */ CMICmdArgValNumber(void); +- /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd); ++ /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask = eArgValNumberFormat_Decimal); + // + bool IsArgNumber(const CMIUtilString &vrTxt) const; + +@@ -61,5 +75,6 @@ + + // Attributes: + private: ++ MIuint m_nNumberFormatMask; + MIint64 m_nNumber; + }; +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 228328) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -565,7 +565,7 @@ + bOk = + bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); +- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true, CMICmdArgValNumber::eArgValNumberFormat_Auto))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true))); + return (bOk && ParseValidateCmdOptions()); + } +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 228328) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -449,6 +449,29 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Check if *this string is a hexadecimal number. ++// Type: Method. ++// Args: None. ++// Return: bool - True = yes number, false not a number. ++// Throws: None. ++//-- ++bool ++CMIUtilString::IsHexadecimalNumber(void) const ++{ ++ if (this->empty()) ++ return false; ++ ++ if ((length() <= 2) || (at(0) != '0') || (at(1) != 'x')) ++ return false; ++ ++ const MIint nPos = find_first_not_of("01234567890ABCDEFabcedf", 2); // Skip '0x..' prefix ++ if (nPos != (MIint)std::string::npos) ++ return false; ++ ++ return true; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Extract the number from the string. The number can be either a hexadecimal or + // natural number. It cannot contain other non-numeric characters. + // Type: Method. +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 228328) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -58,6 +58,7 @@ + bool ExtractNumber(MIint64 &vwrNumber) const; + CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const; + bool IsNumber(void) const; ++ bool IsHexadecimalNumber(void) const; + bool IsQuoted(void) const; + CMIUtilString RemoveRepeatedCharacters(const MIchar vChar); + MIuint Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const; Index: patches/lldbmi_fix_data_read_memory_bytes_hex_format.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_data_read_memory_bytes_hex_format.v2.patch @@ -0,0 +1,270 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 229102) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -37,6 +37,34 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_data_read_memory_bytes(self): ++ """Test that 'lldb-mi --interpreter' works for -data-read-memory-bytes.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Get address of s_RawData ++ self.runCmd("-data-evaluate-expression &s_RawData") ++ self.expect("\^done,value=\"0x[0-9a-f]+\"",timeout=1) ++ addr = int(self.child.after.split("\"")[1], 16) ++ size = 5 ++ ++ # Test -data-read-memory-bytes: try to read data of s_RawData ++ self.runCmd("-data-read-memory-bytes %#x %d" % (addr, size)) ++ self.expect("\^done,memory=\[{begin=\"0x0*%x\",offset=\"0x0+\",end=\"0x0*%x\",contents=\"1234567800\"}\]" % (addr, addr + size)) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_data_list_register_names(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" + +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 229102) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -15,6 +15,8 @@ + int doloop, dosegfault; + int g_MyVar = 3; + static int s_MyVar = 4; ++//FIXME -data-evaluate-expression/print can't evaluate value of type "static char[]" ++const char s_RawData[] = "\x12\x34\x56\x78"; //FIXME static const char s_RawData[] = "\x12\x34\x56\x78"; + + int main (int argc, char const *argv[]) + { +Index: tools/lldb-mi/MICmdArgValNumber.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.cpp (revision 229102) ++++ tools/lldb-mi/MICmdArgValNumber.cpp (working copy) +@@ -31,21 +31,25 @@ + // Throws: None. + //-- + CMICmdArgValNumber::CMICmdArgValNumber(void) +- : m_nNumber(0) ++ : m_nNumberFormatMask(CMICmdArgValNumber::eArgValNumberFormat_Decimal) ++ , m_nNumber(0) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdArgValNumber constructor. + // Type: Method. +-// Args: vrArgName - (R) Argument's name to search by. +-// vbMandatory - (R) True = Yes must be present, false = optional argument. +-// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// Args: vrArgName - (R) Argument's name to search by. ++// vbMandatory - (R) True = Yes must be present, false = optional argument. ++// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// vnNumberFormatMask - (R) Mask of the number formats. (Dflt = CMICmdArgValNumber::eArgValNumberFormat_Decimal) + // Return: None. + // Throws: None. + //-- +-CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd) ++CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask /* = CMICmdArgValNumber::eArgValNumberFormat_Decimal*/) + : CMICmdArgValBaseTemplate(vrArgName, vbMandatory, vbHandleByCmd) ++ , m_nNumberFormatMask(vnNumberFormatMask) + , m_nNumber(0) + { + } +@@ -128,11 +132,20 @@ + bool + CMICmdArgValNumber::IsArgNumber(const CMIUtilString &vrTxt) const + { ++ const bool bFormatDecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Decimal); ++ const bool bFormatHexadecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Hexadecimal); ++ + // Look for --someLongOption + if (std::string::npos != vrTxt.find("--")) + return false; + +- return vrTxt.IsNumber(); ++ if (bFormatDecimal && vrTxt.IsNumber()) ++ return true; ++ ++ if (bFormatHexadecimal && vrTxt.IsHexadecimalNumber()) ++ return true; ++ ++ return false; + } + + //++ ------------------------------------------------------------------------------------ +@@ -150,7 +163,7 @@ + bool bOk = vrTxt.ExtractNumber(nNumber); + if (bOk) + { +- m_nNumber = static_cast(nNumber); ++ m_nNumber = static_cast(nNumber); + } + + return bOk; +Index: tools/lldb-mi/MICmdArgValNumber.h +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.h (revision 229102) ++++ tools/lldb-mi/MICmdArgValNumber.h (working copy) +@@ -40,10 +40,24 @@ + //-- + class CMICmdArgValNumber : public CMICmdArgValBaseTemplate + { ++ // Enums: ++ public: ++ //++ --------------------------------------------------------------------------------- ++ // Details: CMICmdArgValNumber needs to know what format of argument to look for in ++ // the command options text. ++ //-- ++ enum ArgValNumberFormat_e ++ { ++ eArgValNumberFormat_Decimal = (1u << 0), ++ eArgValNumberFormat_Hexadecimal = (1u << 1), ++ eArgValNumberFormat_Auto = ((eArgValNumberFormat_Hexadecimal << 1) - 1u) ///< Indicates to try and lookup everything up during a query. ++ }; ++ + // Methods: + public: + /* ctor */ CMICmdArgValNumber(void); +- /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd); ++ /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask = eArgValNumberFormat_Decimal); + // + bool IsArgNumber(const CMIUtilString &vrTxt) const; + +@@ -61,5 +75,6 @@ + + // Attributes: + private: ++ MIuint m_nNumberFormatMask; + MIint64 m_nNumber; + }; +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 229102) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -568,7 +568,7 @@ + bOk = + bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); +- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true, CMICmdArgValNumber::eArgValNumberFormat_Auto))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -640,13 +640,13 @@ + CMICmdCmdDataReadMemoryBytes::Acknowledge(void) + { + // MI: memory=[{begin=\"0x%08x\",offset=\"0x%08x\",end=\"0x%08x\",contents=\" \" }]" +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08x", m_nAddrStart)); ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08llx", m_nAddrStart)); + const CMICmnMIValueResult miValueResult("begin", miValueConst); + CMICmnMIValueTuple miValueTuple(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08x", m_nAddrOffset)); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08llx", m_nAddrOffset)); + const CMICmnMIValueResult miValueResult2("offset", miValueConst2); + miValueTuple.Add(miValueResult2); +- const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08x", m_nAddrStart + m_nAddrNumBytesToRead)); ++ const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08llx", m_nAddrStart + m_nAddrNumBytesToRead)); + const CMICmnMIValueResult miValueResult3("end", miValueConst3); + miValueTuple.Add(miValueResult3); + +@@ -655,7 +655,7 @@ + strContent.reserve((m_nAddrNumBytesToRead << 1) + 1); + for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++) + { +- strContent += CMIUtilString::Format("%02x", m_pBufferMemory[i]); ++ strContent += CMIUtilString::Format("%02hhx", m_pBufferMemory[i]); + } + const CMICmnMIValueConst miValueConst4(strContent); + const CMICmnMIValueResult miValueResult4("contents", miValueConst4); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 229102) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -23,7 +23,7 @@ + #include // std::unique_ptr + #include // va_list, va_start, var_end + #include // std::stringstream +-#include // for strcpy ++#include // for strncmp + #include // for ULONG_MAX + + // In-house headers: +@@ -395,6 +395,26 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Check if *this string is a hexadecimal number. ++// Type: Method. ++// Args: None. ++// Return: bool - True = yes number, false not a number. ++// Throws: None. ++//-- ++bool ++CMIUtilString::IsHexadecimalNumber(void) const ++{ ++ if ((strncmp(c_str(), "0x", 2) != 0) && (strncmp(c_str(), "0X", 2) != 0)) // Compare '0x..' prefix ++ return false; ++ ++ const MIint nPos = find_first_not_of("01234567890ABCDEFabcedf", 2); // Skip '0x..' prefix ++ if (nPos != (MIint)std::string::npos) ++ return false; ++ ++ return true; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Extract the number from the string. The number can be either a hexadecimal or + // natural number. It cannot contain other non-numeric characters. + // Type: Method. +@@ -433,17 +453,16 @@ + { + vwrNumber = 0; + +- const MIint nPos = find_first_not_of("x01234567890ABCDEFabcedf"); ++ const MIint nPos = find_first_not_of("xX01234567890ABCDEFabcedf"); + if (nPos != (MIint)std::string::npos) + return false; + +- const MIint64 nNum = ::strtoul(this->c_str(), nullptr, 16); +- if (nNum != LONG_MAX) +- { +- vwrNumber = nNum; +- return true; +- } ++ const MIuint64 nNum = ::strtoull(this->c_str(), nullptr, 16); ++ if (nNum == ULLONG_MAX && errno == ERANGE) ++ return false; + ++ vwrNumber = static_cast(nNum); ++ + return true; + } + +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 229102) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -58,6 +58,7 @@ + bool ExtractNumber(MIint64 &vwrNumber) const; + CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const; + bool IsNumber(void) const; ++ bool IsHexadecimalNumber(void) const; + bool IsQuoted(void) const; + CMIUtilString RemoveRepeatedCharacters(const MIchar vChar); + MIuint Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const; Index: patches/lldbmi_fix_data_read_memory_bytes_hex_format.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_data_read_memory_bytes_hex_format.v3.patch @@ -0,0 +1,370 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 229110) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -37,6 +37,34 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_data_read_memory_bytes(self): ++ """Test that 'lldb-mi --interpreter' works for -data-read-memory-bytes.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Get address of s_RawData ++ self.runCmd("-data-evaluate-expression &s_RawData") ++ self.expect("\^done,value=\"0x[0-9a-f]+\"",timeout=1) ++ addr = int(self.child.after.split("\"")[1], 16) ++ size = 5 ++ ++ # Test -data-read-memory-bytes: try to read data of s_RawData ++ self.runCmd("-data-read-memory-bytes %#x %d" % (addr, size)) ++ self.expect("\^done,memory=\[{begin=\"0x0*%x\",offset=\"0x0+\",end=\"0x0*%x\",contents=\"1234567800\"}\]" % (addr, addr + size)) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_data_list_register_names(self): + """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" + +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 229110) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -152,22 +152,22 @@ + # Test -exec-next + self.runCmd("-exec-next --thread 1 --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"26\"") + + # Test that --thread is optional + self.runCmd("-exec-next --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") + + # Test that --frame is optional + self.runCmd("-exec-next --thread 1") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"29\"") + + # Test that both --thread and --frame are optional + self.runCmd("-exec-next --thread 1") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"29\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"31\"") + + # Test that an invalid --thread is handled + self.runCmd("-exec-next --thread 0") +@@ -204,23 +204,23 @@ + # Test -exec-next-instruction + self.runCmd("-exec-next-instruction --thread 1 --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") + + # Test that --thread is optional + self.runCmd("-exec-next-instruction --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") + + # Test that --frame is optional + self.runCmd("-exec-next-instruction --thread 1") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") + + # Test that both --thread and --frame are optional + self.runCmd("-exec-next-instruction --thread 1") + self.expect("\^running") + # Depending on compiler, it can stop at different line. +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[2-4]\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[4-6]\"") + + # Test that an invalid --thread is handled + self.runCmd("-exec-next-instruction --thread 0") +@@ -259,7 +259,7 @@ + #FIXME: is this supposed to step into printf? + self.runCmd("-exec-step --thread 1 --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"26\"") + + # Test that -exec-step steps into a_MyFunction and back out + # (and that --thread is optional) +@@ -274,10 +274,10 @@ + # -exec-step can keep us in the a_MyFunction for gcc + self.runCmd("-exec-finish --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"24\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"26\"") + self.runCmd("-exec-step --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") + + # Test that -exec-step steps into b_MyFunction + # (and that --frame is optional) +@@ -329,13 +329,13 @@ + # instruction + self.runCmd("-exec-step-instruction --thread 1 --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[2-4]\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[4-6]\"") + + # Test that -exec-step-instruction steps over non branching + # instruction (and that --thread is optional) + self.runCmd("-exec-step-instruction --frame 0") + self.expect("\^running") +- self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[2-4]\"") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"2[4-6]\"") + + # Test that -exec-step-instruction steps into a_MyFunction + # (and that --frame is optional) +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 229110) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -15,6 +15,8 @@ + int doloop, dosegfault; + int g_MyVar = 3; + static int s_MyVar = 4; ++//FIXME -data-evaluate-expression/print can't evaluate value of type "static char[]" ++const char s_RawData[] = "\x12\x34\x56\x78"; //FIXME static const char s_RawData[] = "\x12\x34\x56\x78"; + + int main (int argc, char const *argv[]) + { +Index: tools/lldb-mi/MICmdArgValNumber.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.cpp (revision 229110) ++++ tools/lldb-mi/MICmdArgValNumber.cpp (working copy) +@@ -31,21 +31,25 @@ + // Throws: None. + //-- + CMICmdArgValNumber::CMICmdArgValNumber(void) +- : m_nNumber(0) ++ : m_nNumberFormatMask(CMICmdArgValNumber::eArgValNumberFormat_Decimal) ++ , m_nNumber(0) + { + } + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmdArgValNumber constructor. + // Type: Method. +-// Args: vrArgName - (R) Argument's name to search by. +-// vbMandatory - (R) True = Yes must be present, false = optional argument. +-// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// Args: vrArgName - (R) Argument's name to search by. ++// vbMandatory - (R) True = Yes must be present, false = optional argument. ++// vbHandleByCmd - (R) True = Command processes *this option, false = not handled. ++// vnNumberFormatMask - (R) Mask of the number formats. (Dflt = CMICmdArgValNumber::eArgValNumberFormat_Decimal) + // Return: None. + // Throws: None. + //-- +-CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd) ++CMICmdArgValNumber::CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask /* = CMICmdArgValNumber::eArgValNumberFormat_Decimal*/) + : CMICmdArgValBaseTemplate(vrArgName, vbMandatory, vbHandleByCmd) ++ , m_nNumberFormatMask(vnNumberFormatMask) + , m_nNumber(0) + { + } +@@ -128,11 +132,20 @@ + bool + CMICmdArgValNumber::IsArgNumber(const CMIUtilString &vrTxt) const + { ++ const bool bFormatDecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Decimal); ++ const bool bFormatHexadecimal(m_nNumberFormatMask & CMICmdArgValNumber::eArgValNumberFormat_Hexadecimal); ++ + // Look for --someLongOption + if (std::string::npos != vrTxt.find("--")) + return false; + +- return vrTxt.IsNumber(); ++ if (bFormatDecimal && vrTxt.IsNumber()) ++ return true; ++ ++ if (bFormatHexadecimal && vrTxt.IsHexadecimalNumber()) ++ return true; ++ ++ return false; + } + + //++ ------------------------------------------------------------------------------------ +@@ -150,7 +163,7 @@ + bool bOk = vrTxt.ExtractNumber(nNumber); + if (bOk) + { +- m_nNumber = static_cast(nNumber); ++ m_nNumber = static_cast(nNumber); + } + + return bOk; +Index: tools/lldb-mi/MICmdArgValNumber.h +=================================================================== +--- tools/lldb-mi/MICmdArgValNumber.h (revision 229110) ++++ tools/lldb-mi/MICmdArgValNumber.h (working copy) +@@ -40,10 +40,24 @@ + //-- + class CMICmdArgValNumber : public CMICmdArgValBaseTemplate + { ++ // Enums: ++ public: ++ //++ --------------------------------------------------------------------------------- ++ // Details: CMICmdArgValNumber needs to know what format of argument to look for in ++ // the command options text. ++ //-- ++ enum ArgValNumberFormat_e ++ { ++ eArgValNumberFormat_Decimal = (1u << 0), ++ eArgValNumberFormat_Hexadecimal = (1u << 1), ++ eArgValNumberFormat_Auto = ((eArgValNumberFormat_Hexadecimal << 1) - 1u) ///< Indicates to try and lookup everything up during a query. ++ }; ++ + // Methods: + public: + /* ctor */ CMICmdArgValNumber(void); +- /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd); ++ /* ctor */ CMICmdArgValNumber(const CMIUtilString &vrArgName, const bool vbMandatory, const bool vbHandleByCmd, ++ const MIuint vnNumberFormatMask = eArgValNumberFormat_Decimal); + // + bool IsArgNumber(const CMIUtilString &vrTxt) const; + +@@ -61,5 +75,6 @@ + + // Attributes: + private: ++ MIuint m_nNumberFormatMask; + MIint64 m_nNumber; + }; +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 229110) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -568,7 +568,7 @@ + bOk = + bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); +- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true, CMICmdArgValNumber::eArgValNumberFormat_Auto))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -640,13 +640,13 @@ + CMICmdCmdDataReadMemoryBytes::Acknowledge(void) + { + // MI: memory=[{begin=\"0x%08x\",offset=\"0x%08x\",end=\"0x%08x\",contents=\" \" }]" +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08x", m_nAddrStart)); ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%08llx", m_nAddrStart)); + const CMICmnMIValueResult miValueResult("begin", miValueConst); + CMICmnMIValueTuple miValueTuple(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08x", m_nAddrOffset)); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%08llx", m_nAddrOffset)); + const CMICmnMIValueResult miValueResult2("offset", miValueConst2); + miValueTuple.Add(miValueResult2); +- const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08x", m_nAddrStart + m_nAddrNumBytesToRead)); ++ const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%08llx", m_nAddrStart + m_nAddrNumBytesToRead)); + const CMICmnMIValueResult miValueResult3("end", miValueConst3); + miValueTuple.Add(miValueResult3); + +@@ -655,7 +655,7 @@ + strContent.reserve((m_nAddrNumBytesToRead << 1) + 1); + for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++) + { +- strContent += CMIUtilString::Format("%02x", m_pBufferMemory[i]); ++ strContent += CMIUtilString::Format("%02hhx", m_pBufferMemory[i]); + } + const CMICmnMIValueConst miValueConst4(strContent); + const CMICmnMIValueResult miValueResult4("contents", miValueConst4); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 229110) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -23,7 +23,7 @@ + #include // std::unique_ptr + #include // va_list, va_start, var_end + #include // std::stringstream +-#include // for strcpy ++#include // for strncmp + #include // for ULONG_MAX + + // In-house headers: +@@ -395,6 +395,28 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Check if *this string is a hexadecimal number. ++// Type: Method. ++// Args: None. ++// Return: bool - True = yes number, false not a number. ++// Throws: None. ++//-- ++bool ++CMIUtilString::IsHexadecimalNumber(void) const ++{ ++ // Compare '0x..' prefix ++ if ((strncmp(c_str(), "0x", 2) != 0) && (strncmp(c_str(), "0X", 2) != 0)) ++ return false; ++ ++ // Skip '0x..' prefix ++ const MIint nPos = find_first_not_of("01234567890ABCDEFabcedf", 2); ++ if (nPos != (MIint)std::string::npos) ++ return false; ++ ++ return true; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Extract the number from the string. The number can be either a hexadecimal or + // natural number. It cannot contain other non-numeric characters. + // Type: Method. +@@ -433,17 +455,17 @@ + { + vwrNumber = 0; + +- const MIint nPos = find_first_not_of("x01234567890ABCDEFabcedf"); ++ const MIint nPos = find_first_not_of("xX01234567890ABCDEFabcedf"); + if (nPos != (MIint)std::string::npos) + return false; + +- const MIint64 nNum = ::strtoul(this->c_str(), nullptr, 16); +- if (nNum != LONG_MAX) +- { +- vwrNumber = nNum; +- return true; +- } ++ errno = 0; ++ const MIuint64 nNum = ::strtoull(this->c_str(), nullptr, 16); ++ if (errno == ERANGE) ++ return false; + ++ vwrNumber = static_cast(nNum); ++ + return true; + } + +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 229110) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -58,6 +58,7 @@ + bool ExtractNumber(MIint64 &vwrNumber) const; + CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const; + bool IsNumber(void) const; ++ bool IsHexadecimalNumber(void) const; + bool IsQuoted(void) const; + CMIUtilString RemoveRepeatedCharacters(const MIchar vChar); + MIuint Split(const CMIUtilString &vDelimiter, VecString_t &vwVecSplits) const; Index: patches/lldbmi_fix_dotest_help_for_plus_m.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_dotest_help_for_plus_m.patch @@ -0,0 +1,13 @@ +Index: test/dotest.py +=================================================================== +--- test/dotest.py (revision 224200) ++++ test/dotest.py (working copy) +@@ -513,7 +513,7 @@ + X('-g', 'If specified, the filterspec by -f is not exclusive, i.e., if a test module does not match the filterspec (testclass.testmethod), the whole module is still admitted to the test suite') + X('-l', "Don't skip long running tests") + X('-m', "Don't do lldb-mi tests") +- X('+m', "Just do lldb-mi tests. Do not specify along with '+m'", dest='plus_m') ++ X('+m', "Just do lldb-mi tests. Do not specify along with '-m'", dest='plus_m') + group.add_argument('-p', metavar='pattern', help='Specify a regexp filename pattern for inclusion in the test suite') + group.add_argument('-X', metavar='directory', help="Exclude a directory from consideration for test discovery. -X types => if 'types' appear in the pathname components of a potential testfile, it will be ignored") + group.add_argument('-G', '--category', metavar='category', action='append', dest='categoriesList', help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.''')) Index: patches/lldbmi_fix_evaluation_commands.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_evaluation_commands.patch @@ -0,0 +1,221 @@ +Index: source/API/SBValue.cpp +=================================================================== +--- source/API/SBValue.cpp (revision 228386) ++++ source/API/SBValue.cpp (working copy) +@@ -608,7 +608,8 @@ + lldb::ValueObjectSP value_sp(GetSP(locker)); + if (value_sp) + { +- result = value_sp->GetValueDidChange (); ++ if (value_sp->UpdateValueIfNeeded(false)) ++ result = value_sp->GetValueDidChange (); + } + if (log) + log->Printf ("SBValue(%p)::GetValueDidChange() => %i", +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 228386) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -137,7 +137,7 @@ + + // Retrieve the --frame option's number + MIuint64 nFrame = UINT64_MAX; +- if (!pArgFrame->GetExpectedOption(nFrame)) ++ if (pArgThread->GetFound() && !pArgFrame->GetExpectedOption(nFrame)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str())); + return MIstatus::failure; +@@ -151,28 +151,41 @@ + nFrame = pOption->GetValue(); + } + +- bool bAutoName = false; +- const CMIUtilString strArgName; ++ m_strVarName = ""; + if (pArgName->GetFound()) + { + const CMIUtilString &rArg = pArgName->GetValue(); +- bAutoName = (rArg == "-"); ++ const bool bAutoName = (rArg == "-"); ++ if (bAutoName) ++ { ++ m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); ++ CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); ++ } ++ else ++ m_strVarName = rArg; + } + ++ bool bCurrentFrame = false; ++ if (pArgFrameAddr->GetFound()) ++ { ++ const CMIUtilString &rStrFrameAddr(pArgFrameAddr->GetValue()); ++ bCurrentFrame = CMIUtilString::Compare(rStrFrameAddr, "*"); ++ if (!bCurrentFrame && (nFrame == UINT64_MAX)) ++ { ++ //FIXME: *addr isn't implemented. Exit with error if --thread isn't specified. ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str())); ++ return MIstatus::failure; ++ } ++ } ++ + const CMIUtilString &rStrExpression(pArgExpression->GetValue()); + m_strExpression = rStrExpression; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- m_strVarName = ""; +- if (bAutoName) +- { +- m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); +- CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); +- } + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadId = thread.GetIndexID(); +- lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); ++ lldb::SBFrame frame = bCurrentFrame ? thread.GetSelectedFrame() : thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) + value = frame.EvaluateExpression(rStrExpression.c_str()); +@@ -260,7 +273,8 @@ + // Throws: None. + //-- + CMICmdCmdVarUpdate::CMICmdCmdVarUpdate(void) +- : m_constStrArgPrintValues("print-values") ++ : m_eVarInfoFormat(CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues) ++ , m_constStrArgPrintValues("print-values") + , m_constStrArgName("name") + , m_bValueChangedArrayType(false) + , m_bValueChangedCompositeType(false) +@@ -297,7 +311,7 @@ + bool + CMICmdCmdVarUpdate::ParseArgs(void) + { +- bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, false))); ++ bool bOk = m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgName, true, true))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -314,6 +328,7 @@ + bool + CMICmdCmdVarUpdate::Execute(void) + { ++ CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues); + CMICMDBASE_GETOPTION(pArgName, String, m_constStrArgName); + + const CMIUtilString &rVarObjName(pArgName->GetValue()); +@@ -324,6 +339,14 @@ + return MIstatus::failure; + } + ++ const MIuint nPrintValues = pArgPrintValues->GetValue(); ++ if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ m_eVarInfoFormat = static_cast(nPrintValues); ++ + const CMIUtilString &rVarRealName(varObj.GetNameReal()); + MIunused(rVarRealName); + lldb::SBValue &rValue = const_cast(varObj.GetValue()); +@@ -413,9 +436,12 @@ + const CMICmnMIValueConst miValueConst(m_strValueName); + CMICmnMIValueResult miValueResult("name", miValueConst); + CMICmnMIValueTuple miValueTuple(miValueResult); +- const CMICmnMIValueConst miValueConst2(strValue); +- CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ if (m_eVarInfoFormat != CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues) ++ { ++ const CMICmnMIValueConst miValueConst2(strValue); ++ CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ } + const CMICmnMIValueConst miValueConst3(strInScope); + CMICmnMIValueResult miValueResult3("in_scope", miValueConst3); + miValueTuple.Add(miValueResult3); +@@ -1526,7 +1552,7 @@ + + const CMIUtilString &rVarObjName(pArgName->GetValue()); + CMICmnLLDBDebugSessionInfoVarObj varObj; +- if (CMICmnLLDBDebugSessionInfoVarObj::VarObjGet(rVarObjName, varObj)) ++ if (!CMICmnLLDBDebugSessionInfoVarObj::VarObjGet(rVarObjName, varObj)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_VARIABLE_DOESNOTEXIST), m_cmdData.strMiCmd.c_str(), rVarObjName.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdVar.h +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.h (revision 228386) ++++ tools/lldb-mi/MICmdCmdVar.h (working copy) +@@ -42,6 +42,7 @@ + #include "MICmdBase.h" + #include "MICmnMIValueTuple.h" + #include "MICmnMIValueList.h" ++#include "MICmnLLDBDebugSessionInfo.h" + #include "MICmnLLDBDebugSessionInfoVarObj.h" + + // Declarations: +@@ -129,6 +130,7 @@ + // Attribute: + private: + CMIUtilString m_strValueName; ++ CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e m_eVarInfoFormat; + const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command + const CMIUtilString m_constStrArgName; + bool m_bValueChangedArrayType; // True = yes value changed, false = no change +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 228386) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -130,14 +130,14 @@ + + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValue value = frame.EvaluateExpression(rExpression.c_str()); +- if (!value.IsValid()) ++ if (!value.IsValid() || value.GetError().Fail()) + value = frame.FindVariable(rExpression.c_str()); +- if (!value.IsValid()) ++ const CMICmnLLDBUtilSBValue utilValue(value); ++ if (!utilValue.IsValid() || utilValue.IsValueUnknown()) + { + m_bEvaluatedExpression = false; + return MIstatus::success; + } +- const CMICmnLLDBUtilSBValue utilValue(value); + if (!utilValue.HasName()) + { + if (HaveInvalidCharacterInExpression(rExpression, m_cExpressionInvalidChar)) +@@ -279,16 +279,10 @@ + bool + CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, MIchar &vrwInvalidChar) + { +- bool bFoundInvalidCharInExpression = false; +- vrwInvalidChar = 0x00; +- +- if (vrExpr.at(0) == '\\') +- { +- // Example: Mouse hover over "%5d" expression has \"%5d\" in it +- bFoundInvalidCharInExpression = true; +- vrwInvalidChar = '\\'; +- } +- ++ static const std::string strInvalidCharacters(";#\\"); ++ const size_t nInvalidCharacterOffset = vrExpr.find_first_of(strInvalidCharacters); ++ const bool bFoundInvalidCharInExpression = (nInvalidCharacterOffset != CMIUtilString::npos); ++ vrwInvalidChar = bFoundInvalidCharInExpression ? vrExpr[nInvalidCharacterOffset] : 0x00; + return bFoundInvalidCharInExpression; + } + +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 228386) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -10,7 +10,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("evaluation doesn't work properly") + def test_lldbmi_eval(self): + """Test that 'lldb-mi --interpreter' works for evaluating.""" + Index: patches/lldbmi_fix_first_stopped_message_after_process_launch_s.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_first_stopped_message_after_process_launch_s.patch @@ -0,0 +1,16 @@ +Index: source/Target/Process.cpp +=================================================================== +--- source/Target/Process.cpp (revision 227493) ++++ source/Target/Process.cpp (working copy) +@@ -3121,6 +3121,11 @@ + StartPrivateStateThread (); + + m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); ++ ++ // Target was stopped at entry as was intended. Need to notify the listeners ++ // about it. ++ if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true) ++ m_private_state_broadcaster.BroadcastEvent(event_sp); + } + else if (state == eStateExited) + { Index: patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v2.patch @@ -0,0 +1,90 @@ +Index: source/Target/Process.cpp +=================================================================== +--- source/Target/Process.cpp (revision 227968) ++++ source/Target/Process.cpp (working copy) +@@ -3121,6 +3121,11 @@ + StartPrivateStateThread (); + + m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); ++ ++ // Target was stopped at entry as was intended. Need to notify the listeners ++ // about it. ++ if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true) ++ m_private_state_broadcaster.BroadcastEvent(event_sp); + } + else if (state == eStateExited) + { +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 0) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -0,0 +1,69 @@ ++""" ++Test that the lldb-mi driver nofities user properly. ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiNotificationTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stopped_when_stopatentry_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") #FIXME add thread-id ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_stopatentry_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (remote).""" ++ ++ # Prepare debugserver ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") #FIXME add thread-id ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ ++if __name__ == '__main__': ++ unittest2.main() Index: patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v3.patch @@ -0,0 +1,93 @@ +Index: source/Target/Process.cpp +=================================================================== +--- source/Target/Process.cpp (revision 227968) ++++ source/Target/Process.cpp (working copy) +@@ -3121,6 +3121,11 @@ + StartPrivateStateThread (); + + m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); ++ ++ // Target was stopped at entry as was intended. Need to notify the listeners ++ // about it. ++ if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true) ++ m_private_state_broadcaster.BroadcastEvent(event_sp); + } + else if (state == eStateExited) + { +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 0) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -0,0 +1,72 @@ ++""" ++Test that the lldb-mi driver nofities user properly. ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiNotificationTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stopped_when_stopatentry_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") #FIXME add thread-id ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_stopatentry_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (remote).""" ++ ++ # Prepare debugserver ++ import os, sys ++ lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver")) ++ sys.path.append(lldb_gdbserver_folder) ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",stopped-threads=\"all\"") #FIXME add thread-id ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ ++if __name__ == '__main__': ++ unittest2.main() Index: patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_first_stopped_message_after_process_launch_s.v4.patch @@ -0,0 +1,16 @@ +Index: source/Target/Process.cpp +=================================================================== +--- source/Target/Process.cpp (revision 228146) ++++ source/Target/Process.cpp (working copy) +@@ -3121,6 +3121,11 @@ + StartPrivateStateThread (); + + m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); ++ ++ // Target was stopped at entry as was intended. Need to notify the listeners ++ // about it. ++ if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true) ++ HandlePrivateEvent(event_sp); + } + else if (state == eStateExited) + { Index: patches/lldbmi_fix_mandatory_thread_option.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_mandatory_thread_option.patch @@ -0,0 +1,462 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,75 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiDataTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_datadisassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-disassemble: try to disassemble some address ++ child.sendline("-data-disassemble -s 0x0 -e 0x0 -- 0") ++ child.expect("\^done,asm_insns=\[") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,193 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiExecTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_execstepnext(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-step and -exec-next.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-next ++ child.sendline("-exec-next") ++ child.expect("\^running") ++ child.expect("~\"argc=1") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-step ++ child.sendline("-exec-step") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execfinish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-next ++ child.sendline("-exec-next") ++ child.expect("\^running") ++ child.expect("~\"argc=1") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-step ++ child.sendline("-exec-step") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-finish ++ child.sendline("-exec-finish") ++ child.expect("\^running") ++ child.expect("~\"a is about to return 10.\\\\r\\\\n\"") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execstepnextinstruction(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-step-instruction and -exec-next-instruction.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-step-instruction ++ child.sendline("-exec-step-instruction") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-next-instruction ++ child.sendline("-exec-next-instruction") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -342,7 +342,7 @@ + CMICmdCmdDataDisassemble::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); +@@ -373,7 +373,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -328,7 +328,7 @@ + CMICmdCmdExecNext::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -349,7 +349,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -455,7 +455,7 @@ + CMICmdCmdExecStep::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -476,7 +476,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -582,7 +582,7 @@ + CMICmdCmdExecNextInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -603,7 +603,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -709,7 +709,7 @@ + CMICmdCmdExecStepInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -730,7 +730,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -836,7 +836,7 @@ + CMICmdCmdExecFinish::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + return (bOk && ParseValidateCmdOptions()); +@@ -858,7 +858,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -82,7 +82,7 @@ + CMICmdCmdStackInfoDepth::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgMaxDepth, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -104,7 +104,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -202,7 +202,7 @@ + CMICmdCmdStackListFrames::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameLow, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameHigh, false, true))); + return (bOk && ParseValidateCmdOptions()); +@@ -226,7 +226,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -129,12 +129,11 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } +- m_nThreadId = nThreadId; + + // Retrieve the --frame option's number + MIuint64 nFrame = UINT64_MAX; +@@ -171,7 +170,8 @@ + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } + lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ m_nThreadId = thread.GetThreadID(); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) Index: patches/lldbmi_fix_mandatory_thread_option.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_mandatory_thread_option.v2.patch @@ -0,0 +1,462 @@ +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,75 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiDataTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_datadisassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-disassemble: try to disassemble some address ++ child.sendline("-data-disassemble -s 0x0 -e 0x0 -- 0") ++ child.expect("\^done,asm_insns=\[") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,193 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiExecTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_execstepnext(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-step and -exec-next.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-next ++ child.sendline("-exec-next") ++ child.expect("\^running") ++ child.expect("~\"argc=1") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-step ++ child.sendline("-exec-step") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execfinish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-next ++ child.sendline("-exec-next") ++ child.expect("\^running") ++ child.expect("~\"argc=1") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-step ++ child.sendline("-exec-step") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-finish ++ child.sendline("-exec-finish") ++ child.expect("\^running") ++ child.expect("~\"a is about to return 10.\\\\r\\\\n\"") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_execstepnextinstruction(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-step-instruction and -exec-next-instruction.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -exec-step-instruction ++ child.sendline("-exec-step-instruction") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Test -exec-next-instruction ++ child.sendline("-exec-next-instruction") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -342,7 +342,7 @@ + CMICmdCmdDataDisassemble::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); +@@ -373,7 +373,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -328,7 +328,7 @@ + CMICmdCmdExecNext::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -349,7 +349,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -455,7 +455,7 @@ + CMICmdCmdExecStep::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -476,7 +476,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -582,7 +582,7 @@ + CMICmdCmdExecNextInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -603,7 +603,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -709,7 +709,7 @@ + CMICmdCmdExecStepInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -730,7 +730,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -836,7 +836,7 @@ + CMICmdCmdExecFinish::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + return (bOk && ParseValidateCmdOptions()); +@@ -858,7 +858,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -82,7 +82,7 @@ + CMICmdCmdStackInfoDepth::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgMaxDepth, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -104,7 +104,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -202,7 +202,7 @@ + CMICmdCmdStackListFrames::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameLow, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameHigh, false, true))); + return (bOk && ParseValidateCmdOptions()); +@@ -226,7 +226,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 225982) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -129,12 +129,11 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } +- m_nThreadId = nThreadId; + + // Retrieve the --frame option's number + MIuint64 nFrame = UINT64_MAX; +@@ -171,7 +170,8 @@ + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } + lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ m_nThreadId = thread.GetIndexID(); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) Index: patches/lldbmi_fix_mandatory_thread_option.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_mandatory_thread_option.v3.patch @@ -0,0 +1,964 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 227196) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -42,7 +42,7 @@ + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + +- child.sendline("-break-insert -f a_MyFunction") ++ child.sendline("-break-insert -f b_MyFunction") + child.expect("\^done,bkpt={number=\"1\"") + + child.sendline("-exec-run") +@@ -151,7 +151,7 @@ + child.expect("\*stopped,reason=\"breakpoint-hit\"") + + #break on symbol +- child.sendline("-break-insert a_MyFunction") ++ child.sendline("-break-insert b_MyFunction") + child.expect("\^done,bkpt={number=\"2\"") + + child.sendline("-exec-continue") +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,75 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiDataTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_datadisassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-disassemble: try to disassemble some address ++ child.sendline("-data-disassemble -s 0x0 -e 0x0 -- 0") ++ child.expect("\^done,asm_insns=\[") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 227196) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -60,26 +60,26 @@ + child.expect("\*stopped,reason=\"breakpoint-hit\"") + + #print non-existant variable +- #child.sendline("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} ++ #child.sendline("-var-create var1 --frame 0 * undef") #FIXME: shows undef as {...} + #child.expect("error") + #child.sendline("-data-evaluate-expression undef") #FIXME: gets value="undef" + #child.expect("error") + + #print global "g_MyVar" +- child.sendline("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" ++ child.sendline("-var-create var1 --frame 0 * g_MyVar") #FIXME: shows name=" + child.expect("value=\"3\",type=\"int\"") + #child.sendline("-var-evaluate-expression var1") #FIXME: gets var1 does not exist + child.sendline("-var-show-attributes var1") + child.expect("status=\"editable\"") + child.sendline("-var-delete var1") + child.expect("\^done") +- child.sendline("-var-create var1 --thread 1 --frame 0 * g_MyVar") ++ child.sendline("-var-create var1 --frame 0 * g_MyVar") + child.expect("value=\"3\",type=\"int\"") + + #print static "s_MyVar" and modify + child.sendline("-data-evaluate-expression s_MyVar") + child.expect("value=\"30\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") ++ child.sendline("-var-create var3 --frame 0 * \"s_MyVar=3\"") + child.expect("value=\"3\",type=\"int\"") + child.sendline("-data-evaluate-expression \"s_MyVar=30\"") + child.expect("value=\"30\"") +@@ -87,7 +87,7 @@ + #print local "b" and modify + child.sendline("-data-evaluate-expression b") + child.expect("value=\"20\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"b=3\"") ++ child.sendline("-var-create var3 --frame 0 * \"b=3\"") + child.expect("value=\"3\",type=\"int\"") + child.sendline("-data-evaluate-expression \"b=20\"") + child.expect("value=\"20\"") +@@ -95,13 +95,13 @@ + #print "a + b" + child.sendline("-data-evaluate-expression \"a + b\"") + child.expect("value=\"30\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"a + b\"") ++ child.sendline("-var-create var3 --frame 0 * \"a + b\"") + child.expect("value=\"30\",type=\"int\"") + + #print "argv[0]" + child.sendline("-data-evaluate-expression \"argv[0]\"") + child.expect("value=\"0x") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") ++ child.sendline("-var-create var3 --frame 0 * \"argv[0]\"") + child.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") + + #run to exit +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,450 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiExecTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_exec_next(self): ++ """Test that 'lldb-mi --interpreter' works for stepping.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test -exec-next ++ child.sendline("-exec-next --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that --thread is optional ++ child.sendline("-exec-next --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that --frame is optional ++ child.sendline("-exec-next --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ ++ # Test that both --thread and --frame are optional ++ child.sendline("-exec-next --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") ++ ++ # Test that an invalid --thread is handled ++ child.sendline("-exec-next --thread 0") ++ child.expect("\^error,message=\"error: Thread index 0 is out of range") ++ child.sendline("-exec-next --thread 10") ++ child.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned. ++ child.sendline("-exec-next --frame 10") ++ #child.expect("\^error: Frame index 10 is out of range") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_exec_next_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations. ++ ++ # Test -exec-next-instruction ++ child.sendline("-exec-next-instruction --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --thread is optional ++ child.sendline("-exec-next-instruction --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --frame is optional ++ child.sendline("-exec-next-instruction --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that both --thread and --frame are optional ++ child.sendline("-exec-next-instruction --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that an invalid --thread is handled ++ child.sendline("-exec-next-instruction --thread 0") ++ child.expect("\^error,message=\"error: Thread index 0 is out of range") ++ child.sendline("-exec-next-instruction --thread 10") ++ child.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ child.sendline("-exec-next-instruction --frame 10") ++ #child.expect("\^error: Frame index 10 is out of range") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_exec_step(self): ++ """Test that 'lldb-mi --interpreter' works for stepping into.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # Run to printf call ++ self.line = line_number('main.c', '//BP_printf_call') ++ child.sendline("-break-insert -f main.c:%d" % self.line) ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test that -exec-step does not step into printf (which ++ # has no debug info) ++ # HIN FIXME: is this supposed to step into printf? ++ child.sendline("-exec-step --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step steps into a_MyFunction and back out ++ # (and that --thread is optional) ++ child.sendline("-exec-step --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ # HIN FIXME: is this supposed to step into printf? ++ child.sendline("-exec-step --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ child.sendline("-exec-step --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ child.sendline("-exec-step --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that -exec-step steps into b_MyFunction ++ # (and that --frame is optional) ++ child.sendline("-exec-step --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-step steps into a_MyFunction from inside ++ # b_MyFunction (and that both --thread and --frame are optional) ++ child.sendline("-exec-step") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ child.sendline("-exec-step --thread 0") ++ child.expect("\^error,message=\"error: Thread index 0 is out of range") ++ child.sendline("-exec-step --thread 10") ++ child.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled. ++ # FIXME: no error is returned ++ child.sendline("-exec-step --frame 10") ++ #child.expect("\^error: Frame index 10 is out of range") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin due to calling convention assumptions") ++ def test_lldbmi_exec_step_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping into.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations. ++ ++ # Run to a_MyFunction call ++ self.line = line_number('main.c', '//BP_a_MyFunction_call') ++ child.sendline("-break-insert -f main.c:%d" % self.line) ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction ++ child.sendline("-exec-step-instruction --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction (and that --thread is optional) ++ child.sendline("-exec-step-instruction --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that --frame is optional) ++ child.sendline("-exec-step-instruction --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that both --thread and --frame are optional) ++ child.sendline("-exec-step-instruction --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ child.sendline("-exec-step-instruction --thread 0") ++ child.expect("\^error,message=\"error: Thread index 0 is out of range") ++ child.sendline("-exec-step-instruction --thread 10") ++ child.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned. ++ child.sendline("-exec-step-instruction --frame 10") ++ #child.expect("\^error: Frame index 10 is out of range") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ @unittest2.expectedFailure("requires '-exec-arguments' patch") ++ def test_lldbmi_exec_finish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-file-exec-and-symbols " + self.myexe) ++ child.expect("\^done") ++ ++ # Set argument 'l' ++ child.sendline("-exec-arguments l") ++ child.expect("\^done") ++ ++ # Set BP at a_MyFunction_call and run to BP ++ child.sendline("-break-insert -f a_MyFunction") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction ++ child.sendline("-exec-finish --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Run to BP inside b_MyFunction call ++ self.line = line_number('b.c', '//BP_b_MyFunction') ++ child.sendline("-break-insert -f b.c:%d" % self.line) ++ child.expect("\^done,bkpt={number=\"2\"") ++ child.sendline("-exec-continue") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish hits BP at a_MyFunction call inside ++ # b_MyFunction (and that --thread is optional) ++ child.sendline("-exec-finish --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction call inside ++ # b_MyFunction (and that --frame is optional) ++ child.sendline("-exec-finish --thread 1") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-finish returns from b_MyFunction ++ # (and that both --thread and --frame are optional) ++ child.sendline("-exec-finish") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Test that an invalid --thread is handled ++ child.sendline("-exec-finish --thread 0") ++ child.expect("\^error,message=\"error: Thread index 0 is out of range") ++ child.sendline("-exec-finish --thread 10") ++ child.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled. ++ # FIXME: no error is returned. ++ #child.sendline("-exec-finish --frame 10") ++ #child.expect("\^error: Frame index 10 is out of range") ++ ++ # Set BP at printf and run to BP. ++ # FIXME: BP at printf not resolved and never hit! ++ child.sendline("-interpreter-exec command \"b printf\"") #FIXME: child.sendline("-break-insert -f printf") ++ child.expect("\^done") #FIXME: child.expect("\^done,bkpt={number=\"3\"") ++ child.sendline("-exec-continue") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ ## Test that -exec-finish returns from printf. ++ child.sendline("-exec-finish --thread 1 --frame 0") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 227196) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -117,6 +117,98 @@ + print "\n\nContents of child_read.txt:" + print from_child + ++ @lldbmi_test ++ def test_lldbmi_stackdepth(self): ++ """Test that 'lldb-mi --interpreter' can shows depth of the stack.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack depth ++ child.sendline("-stack-info-depth") ++ child.expect("\^done,depth=\"[1-9]\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_stackframes(self): ++ """Test that 'lldb-mi --interpreter' can lists the frames on the stack.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack frame: get frame #0 info ++ child.sendline("-stack-list-frames 0 0") ++ child.expect("\^done,stack=\[frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\".+\"\}\]") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 227196) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -42,7 +42,7 @@ + child.sendline("000-file-exec-and-symbols " + self.myexe) + child.expect("000\^done") + +- child.sendline("100000001-break-insert -f a_MyFunction") ++ child.sendline("100000001-break-insert -f b_MyFunction") + child.expect("100000001\^done,bkpt={number=\"1\"") + + child.sendline("2-exec-run") +Index: test/tools/lldb-mi/a.c +=================================================================== +--- test/tools/lldb-mi/a.c (revision 227196) ++++ test/tools/lldb-mi/a.c (working copy) +@@ -3,7 +3,6 @@ + int + a_MyFunction () + { +- // Set a breakpoint here. +- printf ("a is about to return 10.\n"); ++ printf ("a is about to return 10.\n"); //BP_a_MyFunction + return 10; + } +Index: test/tools/lldb-mi/b.c +=================================================================== +--- test/tools/lldb-mi/b.c (revision 227196) ++++ test/tools/lldb-mi/b.c (working copy) +@@ -1,9 +1,10 @@ + #include + ++extern int a_MyFunction(); + int + b_MyFunction () + { +- // Set a breakpoint here. ++ (void)a_MyFunction(); //BP_b_MyFunction + printf ("b is about to return 20.\n"); + return 20; + } +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 227196) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -17,9 +17,10 @@ + int main (int argc, char const *argv[]) + { + int a, b; +- printf("argc=%d\n", argc); +- a = a_MyFunction(); +- b = b_MyFunction(); ++ printf("argc=%d\n", argc); //BP_printf_call ++ //BP_argctest ++ a = a_MyFunction(); //BP_a_MyFunction_call ++ b = b_MyFunction(); //BP_b_MyFunction_call + //BP_localstest + if (doloop) + infloop(); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 227196) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -342,7 +342,7 @@ + CMICmdCmdDataDisassemble::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); +@@ -373,7 +373,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 227196) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -328,7 +328,7 @@ + CMICmdCmdExecNext::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -349,7 +349,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -455,7 +455,7 @@ + CMICmdCmdExecStep::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -476,7 +476,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -582,7 +582,7 @@ + CMICmdCmdExecNextInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -603,7 +603,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -709,7 +709,7 @@ + CMICmdCmdExecStepInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -730,7 +730,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -836,7 +836,7 @@ + CMICmdCmdExecFinish::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + return (bOk && ParseValidateCmdOptions()); +@@ -858,7 +858,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 227196) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -82,7 +82,7 @@ + CMICmdCmdStackInfoDepth::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgMaxDepth, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -104,7 +104,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -202,7 +202,7 @@ + CMICmdCmdStackListFrames::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameLow, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameHigh, false, true))); + return (bOk && ParseValidateCmdOptions()); +@@ -226,7 +226,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 227196) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -129,12 +129,11 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } +- m_nThreadId = nThreadId; + + // Retrieve the --frame option's number + MIuint64 nFrame = UINT64_MAX; +@@ -171,7 +170,8 @@ + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } + lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ m_nThreadId = thread.GetIndexID(); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) Index: patches/lldbmi_fix_mandatory_thread_option.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_mandatory_thread_option.v4.patch @@ -0,0 +1,747 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 227493) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -18,7 +18,7 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- self.runCmd("-break-insert -f a_MyFunction") ++ self.runCmd("-break-insert -f b_MyFunction") + self.expect("\^done,bkpt={number=\"1\"") + + self.runCmd("-exec-run") +@@ -71,7 +71,7 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + #break on symbol +- self.runCmd("-break-insert a_MyFunction") ++ self.runCmd("-break-insert b_MyFunction") + self.expect("\^done,bkpt={number=\"2\"") + + self.runCmd("-exec-continue") +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,34 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiDataTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_datadisassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-disassemble: try to disassemble some address ++ self.runCmd("-data-disassemble -s 0x0 -e 0x0 -- 0") ++ self.expect("\^done,asm_insns=\[") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 227493) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -36,26 +36,26 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + #print non-existant variable +- #self.runCmd("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} ++ #self.runCmd("-var-create var1 --frame 0 * undef") #FIXME: shows undef as {...} + #self.expect("error") + #self.runCmd("-data-evaluate-expression undef") #FIXME: gets value="undef" + #self.expect("error") + + #print global "g_MyVar" +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" ++ self.runCmd("-var-create var1 --frame 0 * g_MyVar") #FIXME: shows name=" + self.expect("value=\"3\",type=\"int\"") + #self.runCmd("-var-evaluate-expression var1") #FIXME: gets var1 does not exist + self.runCmd("-var-show-attributes var1") + self.expect("status=\"editable\"") + self.runCmd("-var-delete var1") + self.expect("\^done") +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") ++ self.runCmd("-var-create var1 --frame 0 * g_MyVar") + self.expect("value=\"3\",type=\"int\"") + + #print static "s_MyVar" and modify + self.runCmd("-data-evaluate-expression s_MyVar") + self.expect("value=\"30\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") ++ self.runCmd("-var-create var3 --frame 0 * \"s_MyVar=3\"") + self.expect("value=\"3\",type=\"int\"") + self.runCmd("-data-evaluate-expression \"s_MyVar=30\"") + self.expect("value=\"30\"") +@@ -63,12 +63,12 @@ + #print local "b" and modify + self.runCmd("-data-evaluate-expression b") + self.expect("value=\"20\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"b=3\"") ++ self.runCmd("-var-create var3 --frame 0 * \"b=3\"") + self.expect("value=\"3\",type=\"int\"") + self.runCmd("-data-evaluate-expression \"b=20\"") + self.expect("value=\"20\"") + +- #print "a + b" ++ #print "a + b" in certain thread + self.runCmd("-data-evaluate-expression \"a + b\"") + self.expect("value=\"30\"") + self.runCmd("-var-create var3 --thread 1 --frame 0 * \"a + b\"") +@@ -77,7 +77,7 @@ + #print "argv[0]" + self.runCmd("-data-evaluate-expression \"argv[0]\"") + self.expect("value=\"0x") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") ++ self.runCmd("-var-create var3 --frame 0 * \"argv[0]\"") + self.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") + + #run to exit +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,315 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiExecTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next(self): ++ """Test that 'lldb-mi --interpreter' works for stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test -exec-next ++ self.runCmd("-exec-next --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned. ++ self.runCmd("-exec-next --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations. ++ ++ # Test -exec-next-instruction ++ self.runCmd("-exec-next-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-next-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_step(self): ++ """Test that 'lldb-mi --interpreter' works for stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test that -exec-step does not step into printf (which ++ # has no debug info) ++ self.runCmd("-exec-step --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step steps into a_MyFunction and back out ++ # (and that --thread is optional) ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that -exec-step steps into b_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-step steps into a_MyFunction from inside ++ # b_MyFunction (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled. ++ # FIXME: no error is returned ++ self.runCmd("-exec-step --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin due to calling convention assumptions") ++ def test_lldbmi_exec_step_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations. ++ ++ # Run to a_MyFunction call ++ line = line_number('main.c', '//BP_a_MyFunction_call') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction ++ self.runCmd("-exec-step-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction (and that --thread is optional) ++ self.runCmd("-exec-step-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned. ++ self.runCmd("-exec-step-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.expectedFailure("requires '-exec-arguments' patch") ++ def test_lldbmi_exec_finish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set argument 'l' ++ self.runCmd("-exec-arguments l") ++ self.expect("\^done") ++ ++ # Set BP at a_MyFunction_call and run to BP ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Run to BP inside b_MyFunction call ++ line = line_number('b.c', '//BP_b_MyFunction') ++ self.runCmd("-break-insert -f b.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish hits BP at a_MyFunction call inside ++ # b_MyFunction (and that --thread is optional) ++ self.runCmd("-exec-finish --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction call inside ++ # b_MyFunction (and that --frame is optional) ++ self.runCmd("-exec-finish --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-finish returns from b_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-finish") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-finish --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-finish --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled. ++ # FIXME: no error is returned. ++ #self.runCmd("-exec-finish --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ # Set BP at printf and run to BP. ++ # FIXME: BP at printf not resolved and never hit! ++ self.runCmd("-interpreter-exec command \"b printf\"") #FIXME: self.runCmd("-break-insert -f printf") ++ self.expect("\^done") #FIXME: self.expect("\^done,bkpt={number=\"3\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ ## Test that -exec-finish returns from printf. ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 227493) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -40,7 +40,7 @@ + self.spawnLldbMi(args = None) + + # Load executable +- self.runCmd("-file-exec-and-symbols %s" % (self.myexe)) ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main +@@ -57,5 +57,49 @@ + self.runCmd("-stack-list-locals 1") + self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackdepth(self): ++ """Test that 'lldb-mi --interpreter' can shows depth of the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack depth ++ self.runCmd("-stack-info-depth") ++ self.expect("\^done,depth=\"[1-9]\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackframes(self): ++ """Test that 'lldb-mi --interpreter' can lists the frames on the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack frame: get frame #0 info ++ self.runCmd("-stack-list-frames 0 0") ++ self.expect("\^done,stack=\[frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\"[0-9]+\"\}\]") ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 227493) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -20,7 +20,7 @@ + self.expect("000\^done") + + # Run to main +- self.runCmd("100000001-break-insert -f a_MyFunction") ++ self.runCmd("100000001-break-insert -f b_MyFunction") + self.expect("100000001\^done,bkpt={number=\"1\"") + self.runCmd("2-exec-run") + self.expect("2\^running") +Index: test/tools/lldb-mi/a.c +=================================================================== +--- test/tools/lldb-mi/a.c (revision 227493) ++++ test/tools/lldb-mi/a.c (working copy) +@@ -3,7 +3,6 @@ + int + a_MyFunction () + { +- // Set a breakpoint here. +- printf ("a is about to return 10.\n"); ++ printf ("a is about to return 10.\n"); //BP_a_MyFunction + return 10; + } +Index: test/tools/lldb-mi/b.c +=================================================================== +--- test/tools/lldb-mi/b.c (revision 227493) ++++ test/tools/lldb-mi/b.c (working copy) +@@ -1,9 +1,10 @@ + #include + ++extern int a_MyFunction(); + int + b_MyFunction () + { +- // Set a breakpoint here. ++ (void)a_MyFunction(); //BP_b_MyFunction + printf ("b is about to return 20.\n"); + return 20; + } +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 227493) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -17,9 +17,10 @@ + int main (int argc, char const *argv[]) + { + int a, b; +- printf("argc=%d\n", argc); +- a = a_MyFunction(); +- b = b_MyFunction(); ++ printf("argc=%d\n", argc); //BP_printf_call ++ //BP_argctest ++ a = a_MyFunction(); //BP_a_MyFunction_call ++ b = b_MyFunction(); //BP_b_MyFunction_call + //BP_localstest + if (doloop) + infloop(); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 227493) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -342,7 +342,7 @@ + CMICmdCmdDataDisassemble::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add( + *(new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1))); +@@ -373,7 +373,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 227493) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -328,7 +328,7 @@ + CMICmdCmdExecNext::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -349,7 +349,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -455,7 +455,7 @@ + CMICmdCmdExecStep::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -476,7 +476,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -582,7 +582,7 @@ + CMICmdCmdExecNextInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -603,7 +603,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -709,7 +709,7 @@ + CMICmdCmdExecStepInstruction::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumber, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -730,7 +730,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -836,7 +836,7 @@ + CMICmdCmdExecFinish::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, false, CMICmdArgValListBase::eArgValType_Number, 1))); + return (bOk && ParseValidateCmdOptions()); +@@ -858,7 +858,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 227493) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -82,7 +82,7 @@ + CMICmdCmdStackInfoDepth::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgMaxDepth, false, false))); + return (bOk && ParseValidateCmdOptions()); + } +@@ -104,7 +104,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +@@ -202,7 +202,7 @@ + CMICmdCmdStackListFrames::ParseArgs(void) + { + bool bOk = +- m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, true, true, CMICmdArgValListBase::eArgValType_Number, 1))); ++ m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameLow, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgFrameHigh, false, true))); + return (bOk && ParseValidateCmdOptions()); +@@ -226,7 +226,7 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 227493) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -129,12 +129,11 @@ + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +- if (!pArgThread->GetExpectedOption(nThreadId)) ++ if (pArgThread->GetFound() && !pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } +- m_nThreadId = nThreadId; + + // Retrieve the --frame option's number + MIuint64 nFrame = UINT64_MAX; +@@ -171,7 +170,8 @@ + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } + lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ m_nThreadId = thread.GetIndexID(); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) Index: patches/lldbmi_fix_midriver_comments.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_midriver_comments.patch @@ -0,0 +1,16 @@ +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 224992) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -175,8 +175,8 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) + }; Index: patches/lldbmi_fix_prompt_gdb.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.patch @@ -0,0 +1,198 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223183) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(true); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223183) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,7 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) ++ , m_bShowPrompt(true) + , m_bRedrawPrompt(true) + , m_pStdinReadHandler(nullptr) + { +@@ -278,12 +278,12 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } ++// if (m_bShowPrompt && m_bRedrawPrompt) ++// { ++// CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++// rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); ++// m_bRedrawPrompt = false; ++// } + + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) +@@ -338,7 +338,7 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; ++// m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223183) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -236,3 +236,28 @@ + + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = false) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = false */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ const bool bPromptEnabled = rStdinMan.GetEnablePrompt(); ++ if (bPromptEnabled) ++ { ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ const bool bLock = !vbLockStream || rStdoutMan.Lock(); ++ const bool bOk = bLock && rStdoutMan.WriteMIResponse(rStdinMan.GetPrompt()); ++ !vbLockStream || bLock && rStdoutMan.Unlock(); ++ return bOk; ++ } ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223183) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -43,6 +43,7 @@ + // Statics: + public: + static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool WritePrompt(const bool vbLockStream = false); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223183) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,9 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ CMICmnStreamStdout::WritePrompt(); ++// if (bOk && m_rStdin.GetEnablePrompt()) ++// m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1244,7 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v2.patch @@ -0,0 +1,196 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223240) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(true); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(true); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223240) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,7 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) ++ , m_bShowPrompt(true) + , m_bRedrawPrompt(true) + , m_pStdinReadHandler(nullptr) + { +@@ -278,13 +278,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +331,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223240) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -236,3 +236,31 @@ + + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = false) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = false */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ const bool bPromptEnabled = rStdinMan.GetEnablePrompt(); ++ if (bPromptEnabled) ++ { ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ const bool bLock = !vbLockStream || rStdoutMan.Lock(); ++ const bool bOk = bLock && rStdoutMan.WriteMIResponse(rStdinMan.GetPrompt()); ++ if (vbLockStream && bLock) ++ { ++ rStdoutMan.Unlock(); ++ } ++ return bOk; ++ } ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223240) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -43,6 +43,7 @@ + // Statics: + public: + static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool WritePrompt(const bool vbLockStream = false); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223240) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,10 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ CMICmnStreamStdout::WritePrompt(); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1245,7 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v3.patch @@ -0,0 +1,229 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223355) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -118,6 +118,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,43 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) + // Return: MIstatus::success - Functionality succeeded. + // MIstatus::failure - Functionality failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ { ++ return rStdoutMan.WriteMIResponse(vrTxt); ++ } + ++ const bool bLock = rStdoutMan.Lock(); ++ const bool bOk = bLock && rStdoutMan.WriteMIResponse(vrTxt); ++ bLock && rStdoutMan.Unlock(); + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ { ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ } ++ return bOk; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,8 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223355) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ bOk = CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1246,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePrompt(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v4.patch @@ -0,0 +1,229 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223355) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -118,6 +118,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,43 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) + // Return: MIstatus::success - Functionality succeeded. + // MIstatus::failure - Functionality failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ { ++ return rStdoutMan.WriteMIResponse(vrTxt); ++ } + ++ const bool bLock = rStdoutMan.Lock(); ++ const bool bOk = bLock && rStdoutMan.WriteMIResponse(vrTxt); ++ bLock && rStdoutMan.Unlock(); + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ { ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ } ++ return bOk; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223355) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,8 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223355) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1246,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePrompt(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v5.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v5.patch @@ -0,0 +1,412 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 223770) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -28,7 +28,7 @@ + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -41,24 +41,26 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f a_MyFunction") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -74,16 +76,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_pendbreakonsrc(self): + """Test that 'lldb-mi --interpreter' works for pending source breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -96,27 +95,29 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + + # Find the line number to break inside main() and set + # pending BP. + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -132,16 +133,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_breakpoints(self): + """Test that 'lldb-mi --interpreter' works for breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -154,42 +152,50 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol ++ # Break on symbol ++ child.expect_exact(prompt) + child.sendline("-break-insert a_MyFunction") + child.expect("\^done,bkpt={number=\"2\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source ++ # Break on source + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"3\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit ++ # Run to exit ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -205,10 +211,6 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- +- + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223770) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -118,6 +118,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,43 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) + // Return: MIstatus::success - Functionality succeeded. + // MIstatus::failure - Functionality failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ { ++ return rStdoutMan.WriteMIResponse(vrTxt); ++ } + ++ const bool bLock = rStdoutMan.Lock(); ++ const bool bOk = bLock && rStdoutMan.WriteMIResponse(vrTxt); ++ bLock && rStdoutMan.Unlock(); + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ { ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ } ++ return bOk; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,8 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223770) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1246,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePrompt(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v6.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v6.patch @@ -0,0 +1,411 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 223770) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -28,7 +28,7 @@ + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -41,24 +41,26 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f a_MyFunction") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -74,16 +76,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_pendbreakonsrc(self): + """Test that 'lldb-mi --interpreter' works for pending source breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -96,27 +95,29 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + + # Find the line number to break inside main() and set + # pending BP. + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -132,16 +133,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_breakpoints(self): + """Test that 'lldb-mi --interpreter' works for breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -154,42 +152,50 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol ++ # Break on symbol ++ child.expect_exact(prompt) + child.sendline("-break-insert a_MyFunction") + child.expect("\^done,bkpt={number=\"2\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source ++ # Break on source + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"3\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit ++ # Run to exit ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -205,10 +211,6 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- +- + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223770) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -118,6 +118,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,42 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) + // Return: MIstatus::success - Functionality succeeded. + // MIstatus::failure - Functionality failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ return rStdoutMan.WriteMIResponse(vrTxt); + ++ bool bOk = rStdoutMan.Lock(); ++ if (bOk) ++ { ++ bOk = rStdoutMan.WriteMIResponse(vrTxt); ++ bOk = rStdoutMan.Unlock() && bOk; ++ } + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ return bOk; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 223770) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,8 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 223770) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1243,9 +1246,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePrompt(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v7.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v7.patch @@ -0,0 +1,411 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 224334) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -28,7 +28,7 @@ + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -41,24 +41,26 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f a_MyFunction") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -74,16 +76,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_pendbreakonsrc(self): + """Test that 'lldb-mi --interpreter' works for pending source breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -96,27 +95,29 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + + # Find the line number to break inside main() and set + # pending BP. + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -132,16 +133,13 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + def test_lldbmi_breakpoints(self): + """Test that 'lldb-mi --interpreter' works for breakpoints.""" + import pexpect + self.buildDefault() + +- # The default lldb-mi prompt (seriously?!). ++ # The default lldb-mi prompt. + prompt = "(gdb)" + + # So that the child gets torn down after the test. +@@ -154,42 +152,50 @@ + child.logfile_send = f_send + child.logfile_read = f_read + ++ child.expect_exact(prompt) + child.sendline("-file-exec-and-symbols " + self.myexe) + child.expect("\^done") + ++ child.expect_exact(prompt) + child.sendline("-break-insert -f main") + child.expect("\^done,bkpt={number=\"1\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol ++ # Break on symbol ++ child.expect_exact(prompt) + child.sendline("-break-insert a_MyFunction") + child.expect("\^done,bkpt={number=\"2\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source ++ # Break on source + self.line = line_number('main.c', '//BP_source') ++ child.expect_exact(prompt) + child.sendline("-break-insert main.c:%d" % self.line) + child.expect("\^done,bkpt={number=\"3\"") + ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit ++ # Run to exit ++ child.expect_exact(prompt) + child.sendline("-exec-continue") + child.expect("\^running") ++ child.expect_exact(prompt) + child.expect("\*stopped,reason=\"exited-normally\"") +- child.expect_exact(prompt) + +- child.sendline("quit") +- + # Now that the necessary logging is done, restore logfile to None to + # stop further logging. + child.logfile_send = None +@@ -205,10 +211,6 @@ + print "\n\nContents of child_read.txt:" + print from_child + +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- +- + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 224334) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePrompt(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePrompt(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 224334) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 224334) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -120,6 +120,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 224334) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,42 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) + // Return: MIstatus::success - Functionality succeeded. + // MIstatus::failure - Functionality failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ return rStdoutMan.WriteMIResponse(vrTxt); + ++ bool bOk = rStdoutMan.Lock(); ++ if (bOk) ++ { ++ bOk = rStdoutMan.WriteMIResponse(vrTxt); ++ bOk = rStdoutMan.Unlock() && bOk; ++ } + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ return bOk; ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 224334) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,8 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224334) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1245,9 +1248,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePrompt(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb.v8.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb.v8.patch @@ -0,0 +1,334 @@ +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 0) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -0,0 +1,84 @@ ++""" ++Test that the lldb-mi driver nofities user properly. ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiNotificationTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ def test_lldbmi_prompt(self): ++ """Test that 'lldb-mi --interpreter' echos '(gdb)' after commands and events.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt. ++ prompt = "(gdb)" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.expect_exact(prompt) ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ child.expect_exact(prompt) ++ ++ child.sendline("-break-insert -f a_MyFunction") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.expect_exact(prompt) ++ ++ child.sendline("-exec-run") ++ child.expect("\*running") ++ child.expect_exact(prompt) ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ child.expect_exact(prompt) ++ ++ child.sendline("-exec-continue") ++ child.expect("\^running") ++ child.expect_exact(prompt) ++ child.expect("\*stopped,reason=\"exited-normally\"") ++ child.expect_exact(prompt) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 225039) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -849,7 +849,7 @@ + const CMICmnMIValueResult miValueResult5("frame", miValueTuple); + bOk = bOk && miOutOfBandRecord.Add(miValueResult5); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + } + break; + case 11: // Invalid memory reference. SIGSEGV +@@ -920,7 +920,7 @@ + const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + } + } // switch( nStopReason ) + +@@ -1042,7 +1042,7 @@ + const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); + bOk = bOk && miOutOfBandRecord.Add(miValueResult6); + bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + return bOk; + } + +@@ -1100,7 +1100,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + } + + return MIstatus::success; +@@ -1131,7 +1131,7 @@ + const CMICmnMIValueResult miValueResult2("stopped-threads", miValueConst2); + bOk = miOutOfBandRecord.Add(miValueResult2); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + return bOk; + } + +@@ -1180,7 +1180,7 @@ + const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); + bOk = miOutOfBandRecord.Add(miValueResult9); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + } + + return bOk; +@@ -1272,7 +1272,7 @@ + CMICmnMIValueResult miValueResult("thread-id", miValueConst); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); + bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + + return bOk; + } +@@ -1316,7 +1316,7 @@ + CMICmnMIOutOfBandRecord miOutOfBandRecord3(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4); + bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord3); + } +- bOk = bOk && TextToStdout("(gdb)"); ++ bOk = bOk && CMICmnStreamStdout::WritePromptGdb(); + + return bOk; + } +@@ -1543,7 +1543,7 @@ + ++it; + } + +- return TextToStdout("(gdb)"); ++ return CMICmnStreamStdout::WritePromptGdb(); + } + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 225039) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -46,8 +46,7 @@ + , m_pVisitor(nullptr) + , m_strPromptCurrent("(gdb)") + , m_bKeyCtrlCHit(false) +- , m_bShowPrompt(false) +- , m_bRedrawPrompt(true) ++ , m_bShowPrompt(true) + , m_pStdinReadHandler(nullptr) + { + } +@@ -278,13 +277,6 @@ + bool + CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive) + { +- if (m_bShowPrompt) +- { +- CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); +- rStdoutMan.WriteMIResponse(m_strPromptCurrent.c_str()); +- m_bRedrawPrompt = false; +- } +- + // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM + if (m_bKeyCtrlCHit) + { +@@ -338,7 +330,6 @@ + { + bool bYesExit = false; + bOk = m_pVisitor->ReadLine(CMIUtilString(pText), bYesExit); +- m_bRedrawPrompt = true; + vrwbYesAlive = !bYesExit; + } + +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 225039) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -120,6 +120,5 @@ + CMIUtilString m_strPromptCurrent; // Command line prompt as shown to the user + volatile bool m_bKeyCtrlCHit; // True = User hit Ctrl-C, false = has not yet + bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt +- bool m_bRedrawPrompt; // True = Prompt needs to be redrawn + IOSStdinHandler *m_pStdinReadHandler; + }; +Index: tools/lldb-mi/MICmnStreamStdout.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.cpp (revision 225039) ++++ tools/lldb-mi/MICmnStreamStdout.cpp (working copy) +@@ -222,17 +222,56 @@ + // Details: Take a text data and send to the stdout stream. Also output to the MI Log + // file. + // Type: Static method. +-// Args: vrTxt - (R) Text. +-// Return: MIstatus::success - Functionality succeeded. +-// MIstatus::failure - Functionality failed. ++// Args: vrTxt - (R) Text. ++// vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool +-CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt) ++CMICmnStreamStdout::TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream /* = true */) + { +- const bool bLock = CMICmnStreamStdout::Instance().Lock(); +- const bool bOk = bLock && CMICmnStreamStdout::Instance().WriteMIResponse(vrTxt); +- bLock &&CMICmnStreamStdout::Instance().Unlock(); ++ CMICmnStreamStdout &rStdoutMan = CMICmnStreamStdout::Instance(); ++ if (!vbLockStream) ++ return rStdoutMan.WriteMIResponse(vrTxt); + ++ bool bOk = rStdoutMan.Lock(); ++ if (bOk) ++ { ++ bOk = rStdoutMan.WriteMIResponse(vrTxt); ++ bOk = rStdoutMan.Unlock() && bOk; ++ } + return bOk; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write prompt to stdout if it's enabled. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePrompt(const bool vbLockStream /* = true */) ++{ ++ const CMICmnStreamStdin &rStdinMan = CMICmnStreamStdin::Instance(); ++ bool bOk = MIstatus::success; ++ if (rStdinMan.GetEnablePrompt()) ++ bOk = TextToStdout(rStdinMan.GetPrompt(), vbLockStream); ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Write "(gdb)" to stdout. ++// Type: Static method. ++// Args: vbLockStream - (R) True = Lock stream before writing, false = do not. (Dflt = true) ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdout::WritePromptGdb(const bool vbLockStream /* = true */) ++{ ++ return TextToStdout("(gdb)", vbLockStream); ++} +Index: tools/lldb-mi/MICmnStreamStdout.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdout.h (revision 225039) ++++ tools/lldb-mi/MICmnStreamStdout.h (working copy) +@@ -42,7 +42,9 @@ + + // Statics: + public: +- static bool TextToStdout(const CMIUtilString &vrTxt); ++ static bool TextToStdout(const CMIUtilString &vrTxt, const bool vbLockStream = true); ++ static bool WritePrompt(const bool vbLockStream = true); ++ static bool WritePromptGdb(const bool vbLockStream = true); + + // Methods: + public: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 225039) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -690,8 +690,11 @@ + const bool bOk = InterpretCommand(lineText); + + // Draw prompt if desired +- if (bOk && m_rStdin.GetEnablePrompt()) +- m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ CMICmnStreamStdout::WritePrompt(bLockStream); ++ } + + // Input has been processed + bHaveInput = false; +@@ -1245,9 +1248,8 @@ + bool + CMIDriver::InitClientIDEEclipse(void) const + { +- std::cout << "(gdb)" << std::endl; +- +- return MIstatus::success; ++ const bool bLockStream = false; ++ return CMICmnStreamStdout::WritePromptGdb(bLockStream); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_fix_prompt_gdb_after_s_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb_after_s_support.patch @@ -0,0 +1,36 @@ +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224200) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -21,7 +21,6 @@ + + // Third party headers: + #include // va_list, va_start, var_end +-#include + #include + #include + +@@ -1400,12 +1399,22 @@ + { + // Print command + if (!m_bHaveSourceQuietlyOnCmdLine) +- std::cout << strCommand << std::endl; ++ { ++ const bool bLockStream = false; ++ bOk = CMICmnStreamStdout::TextToStdout(strCommand, bLockStream); ++ } + + // Execute if no error + if (bOk) + bOk = InterpretCommand(strCommand); + ++ // Draw the prompt after command will be executed (if enabled) ++ if (bOk) ++ { ++ const bool bLockStream = false; ++ bOk = CMICmnStreamStdout::WritePrompt(bLockStream); ++ } ++ + // Break if there is + if (!bOk) + { Index: patches/lldbmi_fix_prompt_gdb_when_command_not_found.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb_when_command_not_found.patch @@ -0,0 +1,12 @@ +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 229110) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -1042,6 +1042,7 @@ + const CMICmnMIValueResult valueResult("msg", vconst); + const CMICmnMIResultRecord miResultRecord(cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, valueResult); + m_rStdOut.WriteMIResponse(miResultRecord.GetString()); ++ m_rStdOut.WriteMIResponse("(gdb)"); + + // Proceed to wait for or execute next command + return MIstatus::success; Index: patches/lldbmi_fix_prompt_gdb_when_command_not_found_test.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_prompt_gdb_when_command_not_found_test.patch @@ -0,0 +1,16 @@ +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 229137) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -18,6 +18,11 @@ + # Test that lldb-mi is ready after startup + self.expect(self.child_prompt, exactly = True) + ++ # Test that lldb-mi is ready after unknown command ++ self.runCmd("-unknown-command") ++ self.expect("\^error,msg=\"Driver\. Received command '-unknown-command'\. It was not handled\. Command 'unknown-command' not in Command Factory\"") ++ self.expect(self.child_prompt, exactly = True) ++ + # Test that lldb-mi is ready after -file-exec-and-symbols + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") Index: patches/lldbmi_fix_quotes_parsing.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.patch @@ -0,0 +1,558 @@ +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -123,7 +123,7 @@ + return MIstatus::success; + + if (m_bHandleQuotedString) +- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext)); ++ return ValidateQuotedText(vrwArgContext); + + return ValidateSingleText(vrwArgContext); + } +@@ -140,22 +140,6 @@ + bool + CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext) + { +- if (vrwArgContext.GetNumberArgsPresent() == 1) +- { +- const CMIUtilString &rArg(vrwArgContext.GetArgsLeftToParse()); +- if (IsStringArg(rArg)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = rArg; +- vrwArgContext.RemoveArg(rArg); +- return MIstatus::success; +- } +- else +- return MIstatus::failure; +- } +- +- // More than one option... + const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); + CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); + while (it != vecOptions.end()) +@@ -168,7 +152,7 @@ + if (vrwArgContext.RemoveArg(rArg)) + { + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Unescape(); + return MIstatus::success; + } + else +@@ -184,8 +168,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. Can fall through to +-// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded(). ++// between quotes then delimited by the next space. + // Type: Method. + // Args: vrwArgContext - (RW) The command's argument options string. + // Return: MIstatus::success - Functional succeeded. +@@ -195,44 +178,21 @@ + bool + CMICmdArgValString::ValidateQuotedText(CMICmdArgContext &vrwArgContext) + { +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cQuote = '"'; +- +- // Look for first quote of two +- MIint nPos = strOptions.find(cQuote); +- if (nPos == (MIint)std::string::npos) +- return ValidateSingleText(vrwArgContext); +- +- // Is one and only quote at end of the string +- const MIint nLen = strOptions.length(); +- if (nPos == (MIint)(nLen - 1)) ++ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); ++ if (vecOptions.size() == 0) + return MIstatus::failure; + +- // Quote must be the first character in the string or be preceeded by a space +- if ((nPos > 0) && (strOptions[nPos - 1] != ' ')) ++ const CMIUtilString &rArg(vecOptions[0]); ++ if (!IsStringArg(rArg)) + return MIstatus::failure; + +- // Need to find the other quote +- const MIint nPos2 = strOptions.rfind(cQuote); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; ++ m_bFound = true; + +- // Is there quotes surrounding string formatting embedded quotes +- if (IsStringArgQuotedQuotedTextEmbedded(strOptions)) +- return ValidateQuotedQuotedTextEmbedded(vrwArgContext); +- +- // Make sure not same back quote, need two quotes +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) ++ if (vrwArgContext.RemoveArg(rArg)) + { +- m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const MIchar cQuote = '"'; ++ m_argValue = rArg.Trim(cQuote).Unescape(); + return MIstatus::success; + } + +@@ -240,110 +200,6 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". Can fall through to ValidateQuotedText(). +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cBckSlash = '\\'; +- const MIint nPos = strOptions.find(cBckSlash); +- if (nPos == (MIint)std::string::npos) +- return ValidateQuotedText(vrwArgContext); +- +- // Back slash must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Need to find the other back slash +- const MIint nPos2 = strOptions.rfind(cBckSlash); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- // Make sure not same back slash, need two slashs +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Look for the two quotes +- const MIint nLen = strOptions.length(); +- const MIchar cQuote = '"'; +- const MIint nPosQuote1 = nPos + 1; +- const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2; +- if ((nPosQuote1 != nPosQuote2) && (strOptions[nPosQuote1] != cQuote) && (strOptions[nPosQuote2] != cQuote)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIint nPos = strOptions.find("\"\\\""); +- if (nPos == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nPos2 = strOptions.rfind("\\\"\""); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nLen = strOptions.length(); +- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2))) +- return MIstatus::failure; +- +- // Quote must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ + // Details: Examine the string and determine if it is a valid string type argument. + // Type: Method. + // Args: vrTxt - (R) Some text. +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 223770) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -221,43 +221,33 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; +- } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) ++ // Find next occurrence of the delimiter after section ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos)); ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; ++ ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); + vwVecSplits.push_back(strSection.c_str()); + ++ // Next ++ nOffset = nNextDelimiterPos + 1; ++ } ++ while (nOffset < nLen); ++ + return vwVecSplits.size(); + } + +@@ -280,83 +270,39 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- // Look for more quotes +- bool bHaveQuotes = false; +- const MIchar cBckSlash = '\\'; +- const MIchar cQuote = '"'; +- MIint nPosQ = find(cQuote); +- MIint nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = nPosQ + 1; +- while (nPosQ2 < strLen) ++ // Find next occurrence of the delimiter after (quoted) section ++ const bool bSkipQuotedText(true); ++ bool bUnmatchedQuote(false); ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); ++ if (bUnmatchedQuote) + { +- nPosQ2 = find(cQuote, nPosQ2); +- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash)) +- break; +- nPosQ2++; ++ vwVecSplits.clear(); ++ return 0; + } +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- if (!bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ)))) +- { +- // Extract text or quoted text +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); ++ vwVecSplits.push_back(strSection.c_str()); + +- if (bHaveQuotes && (nPos2 > nPosQ2)) +- { +- // Reset, look for more quotes +- bHaveQuotes = false; +- nPosQ = find(cQuote, nPos); +- nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = find(cQuote, nPosQ + 1); +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } +- } +- } +- else +- { +- // Skip passed text in quotes +- nPos2 = find(vDelimiter, nPosQ2 + 1); +- } ++ // Next ++ nOffset = nNextDelimiterPos + 1; + } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) +- vwVecSplits.push_back(strSection.c_str()); ++ while (nOffset < nLen); + + return vwVecSplits.size(); + } +@@ -696,3 +642,139 @@ + + return true; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which mach to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ return find(vrPattern, vnPos); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which mach to the pattern, but isn't surrounded by quotes. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise. ++// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match and which isn't quoted. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos /* = 0 */) const ++{ ++ vrwbNotFoundClosedQuote = false; ++ ++ if (!vbSkipQuotedText) ++ return FindFirst(vrPattern, vnPos); ++ ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nQuotePos(FindFirstQuote(nPos)); ++ const MIuint nPatternPos(FindFirst(vrPattern, nPos)); ++ if (nQuotePos == (MIuint)std::string::npos) ++ return nPatternPos; ++ ++ const MIuint nQuoteClosedPos = FindFirstQuote(nQuotePos + 1); ++ if (nQuoteClosedPos == (MIuint)std::string::npos) ++ { ++ vrwbNotFoundClosedQuote = true; ++ return (MIuint)std::string::npos; ++ } ++ ++ if ((nPatternPos == (MIuint)std::string::npos) || (nPatternPos < nQuotePos)) ++ return nPatternPos; ++ ++ nPos = nQuoteClosedPos + 1; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which doesn't mach to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first character that doesn't match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ const MIuint nLen(length()); ++ const MIuint nPatternLen(vrPattern.length()); ++ ++ MIuint nPatternPos(vnPos); ++ do ++ { ++ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0); ++ if (!bMatchPattern) ++ return nPatternPos; ++ nPatternPos += nPatternLen; ++ } ++ while (nPatternPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence of not escaped quotation mark in *this string. ++// Type: Method. ++// Args: vnPos - (R) Position of the first character in the string to be considered in the search. ++// Return: MIuint - The position of the quotation mark. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstQuote(const MIuint vnPos) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIchar cQuote('"'); ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nPos)); ++ const MIuint nQuotePos(find(cQuote, nPos)); ++ if ((nBckSlashPos == (MIuint)std::string::npos) || (nQuotePos == (MIuint)std::string::npos)) ++ return nQuotePos; ++ ++ if (nQuotePos < nBckSlashPos) ++ return nQuotePos; ++ ++ // Skip 2 characters: First is '\', second is that which is escaped by '\' ++ nPos = nBckSlashPos + 2; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get unescaped string from *this strign. ++// Type: Method. ++// Args: None. ++// Return: MIuint - The unescaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Unescape(void) const ++{ ++ CMIUtilString strNew(*this); ++ strNew = strNew.FindAndReplace("\\\\", "\\"); ++ strNew = strNew.FindAndReplace("\\\"", "\""); ++ return strNew; ++} +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 223770) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -66,6 +66,11 @@ + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; + CMIUtilString Trim(const MIchar vChar) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos = 0) const; ++ MIuint FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ CMIUtilString Unescape(void) const; + // + CMIUtilString &operator=(const MIchar *vpRhs); + CMIUtilString &operator=(const std::string &vrRhs); +@@ -82,4 +87,5 @@ + private: + bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const; + CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar); ++ MIuint FindFirstQuote(const MIuint vnPos) const; + }; Index: patches/lldbmi_fix_quotes_parsing.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.v2.patch @@ -0,0 +1,605 @@ +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 223770) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -77,7 +77,42 @@ + self.expect(from_child, exe=False, + substrs = ["breakpoint-hit"]) + ++ @lldbmi_test ++ def test_lldbmi_innerquotes(self): ++ """Test that 'lldb-mi --interpreter' handles inner quotes correctly.""" ++ import pexpect ++ self.buildDefault() + ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Try to load executable ++ child.sendline("-interpreter-exec command \"target create \\\"%s\\\"\"" % (self.myexe)) ++ child.expect("Current executable set to '%s'" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -123,7 +123,7 @@ + return MIstatus::success; + + if (m_bHandleQuotedString) +- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext)); ++ return ValidateQuotedText(vrwArgContext); + + return ValidateSingleText(vrwArgContext); + } +@@ -140,22 +140,6 @@ + bool + CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext) + { +- if (vrwArgContext.GetNumberArgsPresent() == 1) +- { +- const CMIUtilString &rArg(vrwArgContext.GetArgsLeftToParse()); +- if (IsStringArg(rArg)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = rArg; +- vrwArgContext.RemoveArg(rArg); +- return MIstatus::success; +- } +- else +- return MIstatus::failure; +- } +- +- // More than one option... + const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); + CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); + while (it != vecOptions.end()) +@@ -168,7 +152,7 @@ + if (vrwArgContext.RemoveArg(rArg)) + { + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Unescape(); + return MIstatus::success; + } + else +@@ -184,8 +168,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. Can fall through to +-// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded(). ++// between quotes then delimited by the next space. + // Type: Method. + // Args: vrwArgContext - (RW) The command's argument options string. + // Return: MIstatus::success - Functional succeeded. +@@ -195,44 +178,21 @@ + bool + CMICmdArgValString::ValidateQuotedText(CMICmdArgContext &vrwArgContext) + { +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cQuote = '"'; +- +- // Look for first quote of two +- MIint nPos = strOptions.find(cQuote); +- if (nPos == (MIint)std::string::npos) +- return ValidateSingleText(vrwArgContext); +- +- // Is one and only quote at end of the string +- const MIint nLen = strOptions.length(); +- if (nPos == (MIint)(nLen - 1)) ++ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); ++ if (vecOptions.size() == 0) + return MIstatus::failure; + +- // Quote must be the first character in the string or be preceeded by a space +- if ((nPos > 0) && (strOptions[nPos - 1] != ' ')) ++ const CMIUtilString &rArg(vecOptions[0]); ++ if (!IsStringArg(rArg)) + return MIstatus::failure; + +- // Need to find the other quote +- const MIint nPos2 = strOptions.rfind(cQuote); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; ++ m_bFound = true; + +- // Is there quotes surrounding string formatting embedded quotes +- if (IsStringArgQuotedQuotedTextEmbedded(strOptions)) +- return ValidateQuotedQuotedTextEmbedded(vrwArgContext); +- +- // Make sure not same back quote, need two quotes +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) ++ if (vrwArgContext.RemoveArg(rArg)) + { +- m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const MIchar cQuote = '"'; ++ m_argValue = rArg.Trim(cQuote).Unescape(); + return MIstatus::success; + } + +@@ -240,110 +200,6 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". Can fall through to ValidateQuotedText(). +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cBckSlash = '\\'; +- const MIint nPos = strOptions.find(cBckSlash); +- if (nPos == (MIint)std::string::npos) +- return ValidateQuotedText(vrwArgContext); +- +- // Back slash must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Need to find the other back slash +- const MIint nPos2 = strOptions.rfind(cBckSlash); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- // Make sure not same back slash, need two slashs +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Look for the two quotes +- const MIint nLen = strOptions.length(); +- const MIchar cQuote = '"'; +- const MIint nPosQuote1 = nPos + 1; +- const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2; +- if ((nPosQuote1 != nPosQuote2) && (strOptions[nPosQuote1] != cQuote) && (strOptions[nPosQuote2] != cQuote)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIint nPos = strOptions.find("\"\\\""); +- if (nPos == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nPos2 = strOptions.rfind("\\\"\""); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nLen = strOptions.length(); +- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2))) +- return MIstatus::failure; +- +- // Quote must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ + // Details: Examine the string and determine if it is a valid string type argument. + // Type: Method. + // Args: vrTxt - (R) Some text. +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 223770) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -221,43 +221,33 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; +- } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) ++ // Find next occurrence of the delimiter after section ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos)); ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; ++ ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); + vwVecSplits.push_back(strSection.c_str()); + ++ // Next ++ nOffset = nNextDelimiterPos + 1; ++ } ++ while (nOffset < nLen); ++ + return vwVecSplits.size(); + } + +@@ -280,83 +270,39 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- // Look for more quotes +- bool bHaveQuotes = false; +- const MIchar cBckSlash = '\\'; +- const MIchar cQuote = '"'; +- MIint nPosQ = find(cQuote); +- MIint nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = nPosQ + 1; +- while (nPosQ2 < strLen) ++ // Find next occurrence of the delimiter after (quoted) section ++ const bool bSkipQuotedText(true); ++ bool bUnmatchedQuote(false); ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); ++ if (bUnmatchedQuote) + { +- nPosQ2 = find(cQuote, nPosQ2); +- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash)) +- break; +- nPosQ2++; ++ vwVecSplits.clear(); ++ return 0; + } +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- if (!bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ)))) +- { +- // Extract text or quoted text +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); ++ vwVecSplits.push_back(strSection.c_str()); + +- if (bHaveQuotes && (nPos2 > nPosQ2)) +- { +- // Reset, look for more quotes +- bHaveQuotes = false; +- nPosQ = find(cQuote, nPos); +- nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = find(cQuote, nPosQ + 1); +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } +- } +- } +- else +- { +- // Skip passed text in quotes +- nPos2 = find(vDelimiter, nPosQ2 + 1); +- } ++ // Next ++ nOffset = nNextDelimiterPos + 1; + } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) +- vwVecSplits.push_back(strSection.c_str()); ++ while (nOffset < nLen); + + return vwVecSplits.size(); + } +@@ -696,3 +642,139 @@ + + return true; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which mach to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ return find(vrPattern, vnPos); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which mach to the pattern, but isn't surrounded by quotes. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise. ++// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match and which isn't quoted. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos /* = 0 */) const ++{ ++ vrwbNotFoundClosedQuote = false; ++ ++ if (!vbSkipQuotedText) ++ return FindFirst(vrPattern, vnPos); ++ ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nQuotePos(FindFirstQuote(nPos)); ++ const MIuint nPatternPos(FindFirst(vrPattern, nPos)); ++ if (nQuotePos == (MIuint)std::string::npos) ++ return nPatternPos; ++ ++ const MIuint nQuoteClosedPos = FindFirstQuote(nQuotePos + 1); ++ if (nQuoteClosedPos == (MIuint)std::string::npos) ++ { ++ vrwbNotFoundClosedQuote = true; ++ return (MIuint)std::string::npos; ++ } ++ ++ if ((nPatternPos == (MIuint)std::string::npos) || (nPatternPos < nQuotePos)) ++ return nPatternPos; ++ ++ nPos = nQuoteClosedPos + 1; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which doesn't mach to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first character that doesn't match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ const MIuint nLen(length()); ++ const MIuint nPatternLen(vrPattern.length()); ++ ++ MIuint nPatternPos(vnPos); ++ do ++ { ++ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0); ++ if (!bMatchPattern) ++ return nPatternPos; ++ nPatternPos += nPatternLen; ++ } ++ while (nPatternPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence of not escaped quotation mark in *this string. ++// Type: Method. ++// Args: vnPos - (R) Position of the first character in the string to be considered in the search. ++// Return: MIuint - The position of the quotation mark. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstQuote(const MIuint vnPos) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIchar cQuote('"'); ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nPos)); ++ const MIuint nQuotePos(find(cQuote, nPos)); ++ if ((nBckSlashPos == (MIuint)std::string::npos) || (nQuotePos == (MIuint)std::string::npos)) ++ return nQuotePos; ++ ++ if (nQuotePos < nBckSlashPos) ++ return nQuotePos; ++ ++ // Skip 2 characters: First is '\', second is that which is escaped by '\' ++ nPos = nBckSlashPos + 2; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get unescaped string from *this strign. ++// Type: Method. ++// Args: None. ++// Return: MIuint - The unescaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Unescape(void) const ++{ ++ CMIUtilString strNew(*this); ++ strNew = strNew.FindAndReplace("\\\\", "\\"); ++ strNew = strNew.FindAndReplace("\\\"", "\""); ++ return strNew; ++} +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 223770) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -66,6 +66,11 @@ + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; + CMIUtilString Trim(const MIchar vChar) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos = 0) const; ++ MIuint FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ CMIUtilString Unescape(void) const; + // + CMIUtilString &operator=(const MIchar *vpRhs); + CMIUtilString &operator=(const std::string &vrRhs); +@@ -82,4 +87,5 @@ + private: + bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const; + CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar); ++ MIuint FindFirstQuote(const MIuint vnPos) const; + }; Index: patches/lldbmi_fix_quotes_parsing.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.v3.patch @@ -0,0 +1,636 @@ +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 223770) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -77,7 +77,42 @@ + self.expect(from_child, exe=False, + substrs = ["breakpoint-hit"]) + ++ @lldbmi_test ++ def test_lldbmi_innerquotes(self): ++ """Test that 'lldb-mi --interpreter' handles inner quotes correctly.""" ++ import pexpect ++ self.buildDefault() + ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Try to load executable ++ child.sendline("-interpreter-exec command \"target create \\\"%s\\\"\"" % (self.myexe)) ++ child.expect("Current executable set to '%s'" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 223770) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -46,7 +46,7 @@ + // Throws: None. + //-- + CMICmdArgValString::CMICmdArgValString(const bool vbAnything) +- : m_bHandleQuotedString(false) ++ : m_bHandleQuotedString(vbAnything ? true : false) + , m_bAcceptNumbers(false) + , m_bHandleDirPaths(false) + , m_bHandleAnything(vbAnything) +@@ -123,7 +123,7 @@ + return MIstatus::success; + + if (m_bHandleQuotedString) +- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext)); ++ return ValidateQuotedText(vrwArgContext); + + return ValidateSingleText(vrwArgContext); + } +@@ -140,22 +140,6 @@ + bool + CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext) + { +- if (vrwArgContext.GetNumberArgsPresent() == 1) +- { +- const CMIUtilString &rArg(vrwArgContext.GetArgsLeftToParse()); +- if (IsStringArg(rArg)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = rArg; +- vrwArgContext.RemoveArg(rArg); +- return MIstatus::success; +- } +- else +- return MIstatus::failure; +- } +- +- // More than one option... + const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); + CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); + while (it != vecOptions.end()) +@@ -168,7 +152,7 @@ + if (vrwArgContext.RemoveArg(rArg)) + { + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Unescape(); + return MIstatus::success; + } + else +@@ -184,8 +168,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. Can fall through to +-// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded(). ++// between quotes then delimited by the next space. + // Type: Method. + // Args: vrwArgContext - (RW) The command's argument options string. + // Return: MIstatus::success - Functional succeeded. +@@ -195,44 +178,21 @@ + bool + CMICmdArgValString::ValidateQuotedText(CMICmdArgContext &vrwArgContext) + { +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cQuote = '"'; +- +- // Look for first quote of two +- MIint nPos = strOptions.find(cQuote); +- if (nPos == (MIint)std::string::npos) +- return ValidateSingleText(vrwArgContext); +- +- // Is one and only quote at end of the string +- const MIint nLen = strOptions.length(); +- if (nPos == (MIint)(nLen - 1)) ++ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); ++ if (vecOptions.size() == 0) + return MIstatus::failure; + +- // Quote must be the first character in the string or be preceeded by a space +- if ((nPos > 0) && (strOptions[nPos - 1] != ' ')) ++ const CMIUtilString &rArg(vecOptions[0]); ++ if (!IsStringArg(rArg)) + return MIstatus::failure; + +- // Need to find the other quote +- const MIint nPos2 = strOptions.rfind(cQuote); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; ++ m_bFound = true; + +- // Is there quotes surrounding string formatting embedded quotes +- if (IsStringArgQuotedQuotedTextEmbedded(strOptions)) +- return ValidateQuotedQuotedTextEmbedded(vrwArgContext); +- +- // Make sure not same back quote, need two quotes +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) ++ if (vrwArgContext.RemoveArg(rArg)) + { +- m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const MIchar cQuote = '"'; ++ m_argValue = rArg.Trim(cQuote).Unescape(); + return MIstatus::success; + } + +@@ -240,110 +200,6 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". Can fall through to ValidateQuotedText(). +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cBckSlash = '\\'; +- const MIint nPos = strOptions.find(cBckSlash); +- if (nPos == (MIint)std::string::npos) +- return ValidateQuotedText(vrwArgContext); +- +- // Back slash must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Need to find the other back slash +- const MIint nPos2 = strOptions.rfind(cBckSlash); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- // Make sure not same back slash, need two slashs +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Look for the two quotes +- const MIint nLen = strOptions.length(); +- const MIchar cQuote = '"'; +- const MIint nPosQuote1 = nPos + 1; +- const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2; +- if ((nPosQuote1 != nPosQuote2) && (strOptions[nPosQuote1] != cQuote) && (strOptions[nPosQuote2] != cQuote)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIint nPos = strOptions.find("\"\\\""); +- if (nPos == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nPos2 = strOptions.rfind("\\\"\""); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nLen = strOptions.length(); +- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2))) +- return MIstatus::failure; +- +- // Quote must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ + // Details: Examine the string and determine if it is a valid string type argument. + // Type: Method. + // Args: vrTxt - (R) Some text. +@@ -373,10 +229,6 @@ + bool + CMICmdArgValString::IsStringArgSingleText(const CMIUtilString &vrTxt) const + { +- // Accept anything as string word +- if (m_bHandleAnything) +- return true; +- + if (!m_bHandleDirPaths) + { + // Look for directory file paths, if found reject +@@ -417,6 +269,10 @@ + bool + CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const + { ++ // Accept anything as string word ++ if (m_bHandleAnything) ++ return true; ++ + // CODETAG_QUOTEDTEXT_SIMILAR_CODE + const MIchar cQuote = '"'; + const MIint nPos = vrTxt.find(cQuote); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 223770) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -221,43 +221,33 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; +- } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) ++ // Find next occurrence of the delimiter after section ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos)); ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; ++ ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); + vwVecSplits.push_back(strSection.c_str()); + ++ // Next ++ nOffset = nNextDelimiterPos + 1; ++ } ++ while (nOffset < nLen); ++ + return vwVecSplits.size(); + } + +@@ -280,83 +270,39 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- // Look for more quotes +- bool bHaveQuotes = false; +- const MIchar cBckSlash = '\\'; +- const MIchar cQuote = '"'; +- MIint nPosQ = find(cQuote); +- MIint nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = nPosQ + 1; +- while (nPosQ2 < strLen) ++ // Find next occurrence of the delimiter after (quoted) section ++ const bool bSkipQuotedText(true); ++ bool bUnmatchedQuote(false); ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); ++ if (bUnmatchedQuote) + { +- nPosQ2 = find(cQuote, nPosQ2); +- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash)) +- break; +- nPosQ2++; ++ vwVecSplits.clear(); ++ return 0; + } +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- if (!bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ)))) +- { +- // Extract text or quoted text +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); ++ vwVecSplits.push_back(strSection.c_str()); + +- if (bHaveQuotes && (nPos2 > nPosQ2)) +- { +- // Reset, look for more quotes +- bHaveQuotes = false; +- nPosQ = find(cQuote, nPos); +- nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = find(cQuote, nPosQ + 1); +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } +- } +- } +- else +- { +- // Skip passed text in quotes +- nPos2 = find(vDelimiter, nPosQ2 + 1); +- } ++ // Next ++ nOffset = nNextDelimiterPos + 1; + } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) +- vwVecSplits.push_back(strSection.c_str()); ++ while (nOffset < nLen); + + return vwVecSplits.size(); + } +@@ -696,3 +642,139 @@ + + return true; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ return find(vrPattern, vnPos); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern, but isn't surrounded by quotes. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise. ++// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match and which isn't quoted. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos /* = 0 */) const ++{ ++ vrwbNotFoundClosedQuote = false; ++ ++ if (!vbSkipQuotedText) ++ return FindFirst(vrPattern, vnPos); ++ ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nQuotePos(FindFirstQuote(nPos)); ++ const MIuint nPatternPos(FindFirst(vrPattern, nPos)); ++ if (nQuotePos == (MIuint)std::string::npos) ++ return nPatternPos; ++ ++ const MIuint nQuoteClosedPos = FindFirstQuote(nQuotePos + 1); ++ if (nQuoteClosedPos == (MIuint)std::string::npos) ++ { ++ vrwbNotFoundClosedQuote = true; ++ return (MIuint)std::string::npos; ++ } ++ ++ if ((nPatternPos == (MIuint)std::string::npos) || (nPatternPos < nQuotePos)) ++ return nPatternPos; ++ ++ nPos = nQuoteClosedPos + 1; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which doesn't match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first character that doesn't match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ const MIuint nLen(length()); ++ const MIuint nPatternLen(vrPattern.length()); ++ ++ MIuint nPatternPos(vnPos); ++ do ++ { ++ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0); ++ if (!bMatchPattern) ++ return nPatternPos; ++ nPatternPos += nPatternLen; ++ } ++ while (nPatternPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence of not escaped quotation mark in *this string. ++// Type: Method. ++// Args: vnPos - (R) Position of the first character in the string to be considered in the search. ++// Return: MIuint - The position of the quotation mark. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstQuote(const MIuint vnPos) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIchar cQuote('"'); ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nPos)); ++ const MIuint nQuotePos(find(cQuote, nPos)); ++ if ((nBckSlashPos == (MIuint)std::string::npos) || (nQuotePos == (MIuint)std::string::npos)) ++ return nQuotePos; ++ ++ if (nQuotePos < nBckSlashPos) ++ return nQuotePos; ++ ++ // Skip 2 characters: First is '\', second is that which is escaped by '\' ++ nPos = nBckSlashPos + 2; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get unescaped string from *this strign. ++// Type: Method. ++// Args: None. ++// Return: MIuint - The unescaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Unescape(void) const ++{ ++ CMIUtilString strNew(*this); ++ strNew = strNew.FindAndReplace("\\\\", "\\"); ++ strNew = strNew.FindAndReplace("\\\"", "\""); ++ return strNew; ++} +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 223770) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -66,6 +66,11 @@ + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; + CMIUtilString Trim(const MIchar vChar) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos = 0) const; ++ MIuint FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ CMIUtilString Unescape(void) const; + // + CMIUtilString &operator=(const MIchar *vpRhs); + CMIUtilString &operator=(const std::string &vrRhs); +@@ -82,4 +87,5 @@ + private: + bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const; + CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar); ++ MIuint FindFirstQuote(const MIuint vnPos) const; + }; Index: patches/lldbmi_fix_quotes_parsing.v4-minimal.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.v4-minimal.patch @@ -0,0 +1,23 @@ +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 224520) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -147,7 +147,7 @@ + { + m_bFound = true; + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Trim('"').Unescape(); + vrwArgContext.RemoveArg(rArg); + return MIstatus::success; + } +@@ -232,7 +232,8 @@ + { + m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const CMIUtilString strEscapedTxt = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ m_argValue = strEscapedTxt.Unescape(); + return MIstatus::success; + } + Index: patches/lldbmi_fix_quotes_parsing.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.v4.patch @@ -0,0 +1,751 @@ +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 224200) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -48,7 +48,6 @@ + child.expect("100000001\^done,bkpt={number=\"1\"") + + child.sendline("2-exec-run") +- child.sendline("") # FIXME: lldb-mi hangs here, so extra return is needed + child.expect("2\^running") + child.expect("\*stopped,reason=\"breakpoint-hit\"") + +@@ -77,7 +76,51 @@ + self.expect(from_child, exe=False, + substrs = ["breakpoint-hit"]) + ++ @unittest2.skip("requires 'CLI' patch") ++ @lldbmi_test ++ def test_lldbmi_specialchars(self): ++ """Test that 'lldb-mi --interpreter' handles complicated strings.""" ++ import pexpect ++ self.buildDefault() + ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Create alias for myexe ++ complicated_myexe = "C--mpl-x file's`s @#$%^&*()_+-={}[]| name" ++ if os.path.exists(complicated_myexe): ++ os.unlink(complicated_myexe) ++ os.symlink(self.myexe, complicated_myexe) ++ escaped_myexe = complicated_myexe.replace("$", "\$").replace("^", "\^").replace("[", "\[").replace("]", "\]") ++ ++ # Try to load executable with complicated filename ++ child.sendline("target create \"%s\"" % (complicated_myexe)) ++ child.expect("Currant executable set to '%s'" % (escaped_myexe)) ++ os.unlink(complicated_myexe) ++ child.expect("\^done") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 224200) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -46,7 +46,7 @@ + // Throws: None. + //-- + CMICmdArgValString::CMICmdArgValString(const bool vbAnything) +- : m_bHandleQuotedString(false) ++ : m_bHandleQuotedString(vbAnything ? true : false) + , m_bAcceptNumbers(false) + , m_bHandleDirPaths(false) + , m_bHandleAnything(vbAnything) +@@ -123,7 +123,7 @@ + return MIstatus::success; + + if (m_bHandleQuotedString) +- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext)); ++ return ValidateQuotedText(vrwArgContext); + + return ValidateSingleText(vrwArgContext); + } +@@ -140,22 +140,6 @@ + bool + CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext) + { +- if (vrwArgContext.GetNumberArgsPresent() == 1) +- { +- const CMIUtilString &rArg(vrwArgContext.GetArgsLeftToParse()); +- if (IsStringArg(rArg)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = rArg; +- vrwArgContext.RemoveArg(rArg); +- return MIstatus::success; +- } +- else +- return MIstatus::failure; +- } +- +- // More than one option... + const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); + CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); + while (it != vecOptions.end()) +@@ -168,7 +152,7 @@ + if (vrwArgContext.RemoveArg(rArg)) + { + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Unescape(); + return MIstatus::success; + } + else +@@ -184,8 +168,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. Can fall through to +-// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded(). ++// between quotes then delimited by the next space. + // Type: Method. + // Args: vrwArgContext - (RW) The command's argument options string. + // Return: MIstatus::success - Functional succeeded. +@@ -195,44 +178,21 @@ + bool + CMICmdArgValString::ValidateQuotedText(CMICmdArgContext &vrwArgContext) + { +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cQuote = '"'; +- +- // Look for first quote of two +- MIint nPos = strOptions.find(cQuote); +- if (nPos == (MIint)std::string::npos) +- return ValidateSingleText(vrwArgContext); +- +- // Is one and only quote at end of the string +- const MIint nLen = strOptions.length(); +- if (nPos == (MIint)(nLen - 1)) ++ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); ++ if (vecOptions.size() == 0) + return MIstatus::failure; + +- // Quote must be the first character in the string or be preceeded by a space +- if ((nPos > 0) && (strOptions[nPos - 1] != ' ')) ++ const CMIUtilString &rArg(vecOptions[0]); ++ if (!IsStringArg(rArg)) + return MIstatus::failure; + +- // Need to find the other quote +- const MIint nPos2 = strOptions.rfind(cQuote); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; ++ m_bFound = true; + +- // Is there quotes surrounding string formatting embedded quotes +- if (IsStringArgQuotedQuotedTextEmbedded(strOptions)) +- return ValidateQuotedQuotedTextEmbedded(vrwArgContext); +- +- // Make sure not same back quote, need two quotes +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) ++ if (vrwArgContext.RemoveArg(rArg)) + { +- m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const MIchar cQuote = '"'; ++ m_argValue = rArg.Trim(cQuote).Unescape(); + return MIstatus::success; + } + +@@ -240,110 +200,6 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". Can fall through to ValidateQuotedText(). +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cBckSlash = '\\'; +- const MIint nPos = strOptions.find(cBckSlash); +- if (nPos == (MIint)std::string::npos) +- return ValidateQuotedText(vrwArgContext); +- +- // Back slash must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Need to find the other back slash +- const MIint nPos2 = strOptions.rfind(cBckSlash); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- // Make sure not same back slash, need two slashs +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Look for the two quotes +- const MIint nLen = strOptions.length(); +- const MIchar cQuote = '"'; +- const MIint nPosQuote1 = nPos + 1; +- const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2; +- if ((nPosQuote1 != nPosQuote2) && (strOptions[nPosQuote1] != cQuote) && (strOptions[nPosQuote2] != cQuote)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIint nPos = strOptions.find("\"\\\""); +- if (nPos == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nPos2 = strOptions.rfind("\\\"\""); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nLen = strOptions.length(); +- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2))) +- return MIstatus::failure; +- +- // Quote must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ + // Details: Examine the string and determine if it is a valid string type argument. + // Type: Method. + // Args: vrTxt - (R) Some text. +@@ -373,10 +229,6 @@ + bool + CMICmdArgValString::IsStringArgSingleText(const CMIUtilString &vrTxt) const + { +- // Accept anything as string word +- if (m_bHandleAnything) +- return true; +- + if (!m_bHandleDirPaths) + { + // Look for directory file paths, if found reject +@@ -417,6 +269,10 @@ + bool + CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const + { ++ // Accept anything as string word ++ if (m_bHandleAnything) ++ return true; ++ + // CODETAG_QUOTEDTEXT_SIMILAR_CODE + const MIchar cQuote = '"'; + const MIint nPos = vrTxt.find(cQuote); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 224200) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -221,43 +221,33 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; +- } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) ++ // Find next occurrence of the delimiter after section ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos)); ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; ++ ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); + vwVecSplits.push_back(strSection.c_str()); + ++ // Next ++ nOffset = nNextDelimiterPos + 1; ++ } ++ while (nOffset < nLen); ++ + return vwVecSplits.size(); + } + +@@ -280,83 +270,39 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- // Look for more quotes +- bool bHaveQuotes = false; +- const MIchar cBckSlash = '\\'; +- const MIchar cQuote = '"'; +- MIint nPosQ = find(cQuote); +- MIint nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = nPosQ + 1; +- while (nPosQ2 < strLen) ++ // Find next occurrence of the delimiter after (quoted) section ++ const bool bSkipQuotedText(true); ++ bool bUnmatchedQuote(false); ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); ++ if (bUnmatchedQuote) + { +- nPosQ2 = find(cQuote, nPosQ2); +- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash)) +- break; +- nPosQ2++; ++ vwVecSplits.clear(); ++ return 0; + } +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- if (!bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ)))) +- { +- // Extract text or quoted text +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); ++ vwVecSplits.push_back(strSection.c_str()); + +- if (bHaveQuotes && (nPos2 > nPosQ2)) +- { +- // Reset, look for more quotes +- bHaveQuotes = false; +- nPosQ = find(cQuote, nPos); +- nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = find(cQuote, nPosQ + 1); +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } +- } +- } +- else +- { +- // Skip passed text in quotes +- nPos2 = find(vDelimiter, nPosQ2 + 1); +- } ++ // Next ++ nOffset = nNextDelimiterPos + 1; + } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) +- vwVecSplits.push_back(strSection.c_str()); ++ while (nOffset < nLen); + + return vwVecSplits.size(); + } +@@ -696,3 +642,232 @@ + + return true; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ return find(vrPattern, vnPos); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern, but isn't surrounded by quotes. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise. ++// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match and which isn't quoted. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos /* = 0 */) const ++{ ++ vrwbNotFoundClosedQuote = false; ++ ++ if (!vbSkipQuotedText) ++ return FindFirst(vrPattern, vnPos); ++ ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nQuotePos(FindFirstQuote(nPos)); ++ const MIuint nPatternPos(FindFirst(vrPattern, nPos)); ++ if (nQuotePos == (MIuint)std::string::npos) ++ return nPatternPos; ++ ++ const MIuint nQuoteClosedPos = FindFirstQuote(nQuotePos + 1); ++ if (nQuoteClosedPos == (MIuint)std::string::npos) ++ { ++ vrwbNotFoundClosedQuote = true; ++ return (MIuint)std::string::npos; ++ } ++ ++ if ((nPatternPos == (MIuint)std::string::npos) || (nPatternPos < nQuotePos)) ++ return nPatternPos; ++ ++ nPos = nQuoteClosedPos + 1; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which doesn't match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first character that doesn't match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ const MIuint nLen(length()); ++ const MIuint nPatternLen(vrPattern.length()); ++ ++ MIuint nPatternPos(vnPos); ++ do ++ { ++ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0); ++ if (!bMatchPattern) ++ return nPatternPos; ++ nPatternPos += nPatternLen; ++ } ++ while (nPatternPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence of not escaped quotation mark in *this string. ++// Type: Method. ++// Args: vnPos - (R) Position of the first character in the string to be considered in the search. ++// Return: MIuint - The position of the quotation mark. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstQuote(const MIuint vnPos) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIchar cQuote('"'); ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nPos)); ++ const MIuint nQuotePos(find(cQuote, nPos)); ++ if ((nBckSlashPos == (MIuint)std::string::npos) || (nQuotePos == (MIuint)std::string::npos)) ++ return nQuotePos; ++ ++ if (nQuotePos < nBckSlashPos) ++ return nQuotePos; ++ ++ // Skip 2 characters: First is '\', second is that which is escaped by '\' ++ nPos = nBckSlashPos + 2; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: List of characters that should be escaped. ++// Type: Member. ++//-- ++const CMIUtilString CMIUtilString::ms_strEscapeCharacters("`\\\t\n'\""); ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get escaped string from *this string. ++// Type: Method. ++// Args: None. ++// Return: CMIUtilString - The escaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Escape(void) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIuint nLen(length()); ++ std::string strNew; ++ strNew.reserve(nLen); ++ MIuint nOffset(0); ++ while (nOffset < nLen) ++ { ++ const MIuint nEscapeCharPos(find_first_of(ms_strEscapeCharacters, nOffset)); ++ const bool bEscapeCharNotFound(nEscapeCharPos == (MIuint)std::string::npos); ++ if (bEscapeCharNotFound) ++ { ++ const MIuint nAppendAll((MIuint)std::string::npos); ++ strNew.append(*this, nOffset, nAppendAll); ++ break; ++ } ++ const MIuint nAppendLen(nEscapeCharPos - nOffset); ++ strNew.append(*this, nOffset, nAppendLen); ++ strNew.push_back(cBckSlash); ++ const MIchar cUnescapedChar(at(nEscapeCharPos)); ++ switch (cUnescapedChar) ++ { ++ case '\t': ++ strNew.push_back('t'); ++ break; ++ case '\n': ++ strNew.push_back('t'); ++ break; ++ default: ++ strNew.push_back(cUnescapedChar); ++ break; ++ } ++ nOffset = nEscapeCharPos + 1; ++ } ++ return CMIUtilString(strNew.c_str());; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get unescaped string from *this string. ++// Type: Method. ++// Args: None. ++// Return: CMIUtilString - The unescaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Unescape(void) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIuint nLen(length()); ++ std::string strNew; ++ strNew.reserve(nLen); ++ MIuint nOffset(0); ++ while (nOffset < nLen) ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nOffset)); ++ const bool bBckSlashNotFound(nBckSlashPos == (MIuint)std::string::npos); ++ if (bBckSlashNotFound) ++ { ++ const MIuint nAppendAll((MIuint)std::string::npos); ++ strNew.append(*this, nOffset, nAppendAll); ++ break; ++ } ++ const MIuint nAppendLen(nBckSlashPos - nOffset); ++ strNew.append(*this, nOffset, nAppendLen); ++ const bool bBckSlashIsLast(nBckSlashPos == nLen); ++ if (bBckSlashIsLast) ++ { ++ strNew.push_back(cBckSlash); ++ break; ++ } ++ const MIchar cEscapedChar(at(nBckSlashPos + 1)); ++ switch (cEscapedChar) ++ { ++ case 't': ++ strNew.push_back('\t'); ++ break; ++ case 'n': ++ strNew.push_back('\n'); ++ break; ++ default: ++ { ++ const MIuint nEscapedCharPos(ms_strEscapeCharacters.find(cEscapedChar)); ++ const bool bEscapedCharNotLegal(nEscapedCharPos == (MIuint)std::string::npos); ++ if (bEscapedCharNotLegal) ++ strNew.push_back(cBckSlash); ++ strNew.push_back(cEscapedChar); ++ break; ++ } ++ } ++ nOffset = nBckSlashPos + 2; ++ } ++ return CMIUtilString(strNew.c_str());; ++} +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 224200) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -66,6 +66,12 @@ + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; + CMIUtilString Trim(const MIchar vChar) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos = 0) const; ++ MIuint FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ CMIUtilString Escape(void) const; ++ CMIUtilString Unescape(void) const; + // + CMIUtilString &operator=(const MIchar *vpRhs); + CMIUtilString &operator=(const std::string &vrRhs); +@@ -82,4 +88,9 @@ + private: + bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const; + CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar); ++ MIuint FindFirstQuote(const MIuint vnPos) const; ++ ++ // Attributes: ++ private: ++ static const CMIUtilString ms_strEscapeCharacters; + }; Index: patches/lldbmi_fix_quotes_parsing.v5.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_quotes_parsing.v5.patch @@ -0,0 +1,770 @@ +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 225612) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -67,6 +67,58 @@ + print "\n\nContents of child_read.txt:" + print from_child + ++ @lldbmi_test ++ def test_lldbmi_specialchars(self): ++ """Test that 'lldb-mi --interpreter' handles complicated strings.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Create alias for myexe ++ complicated_myexe = "C--mpl-x file's`s @#$%^&*()_+-={}[]| name" ++ if os.path.exists(complicated_myexe): ++ os.unlink(complicated_myexe) ++ os.symlink(self.myexe, complicated_myexe) ++ escaped_myexe = complicated_myexe.replace("$", "\$").replace("^", "\^").replace("[", "\[").replace("]", "\]") ++ ++ # Try to load executable with complicated filename ++ child.sendline("-file-exec-and-symbols \"%s\"" % (complicated_myexe)) ++ child.expect("\^done") ++ ++ # Check that it was loaded correctly ++ child.sendline("-break-insert -f a_MyFunction") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Cleanup ++ os.unlink(complicated_myexe) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ + if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() +Index: tools/lldb-mi/MICmdArgValFile.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValFile.cpp (revision 225612) ++++ tools/lldb-mi/MICmdArgValFile.cpp (working copy) +@@ -193,13 +193,14 @@ + bool + CMICmdArgValFile::IsValidChars(const CMIUtilString &vrText) const + { ++ static CMIUtilString s_strSpecialCharacters(".'\"`@#$%^&*()_+-={}[]| "); + const MIchar *pPtr = const_cast(vrText.c_str()); + for (MIuint i = 0; i < vrText.length(); i++, pPtr++) + { + const MIchar c = *pPtr; + if (::isalnum((int)c) == 0) + { +- if ((c != '.') && (c != '-') && (c != '_')) ++ if (s_strSpecialCharacters.find(c) == CMIUtilString::npos) + return false; + } + } +Index: tools/lldb-mi/MICmdArgValString.cpp +=================================================================== +--- tools/lldb-mi/MICmdArgValString.cpp (revision 225612) ++++ tools/lldb-mi/MICmdArgValString.cpp (working copy) +@@ -46,7 +46,7 @@ + // Throws: None. + //-- + CMICmdArgValString::CMICmdArgValString(const bool vbAnything) +- : m_bHandleQuotedString(false) ++ : m_bHandleQuotedString(vbAnything ? true : false) + , m_bAcceptNumbers(false) + , m_bHandleDirPaths(false) + , m_bHandleAnything(vbAnything) +@@ -123,7 +123,7 @@ + return MIstatus::success; + + if (m_bHandleQuotedString) +- return (ValidateQuotedText(vrwArgContext) || ValidateQuotedTextEmbedded(vrwArgContext)); ++ return ValidateQuotedText(vrwArgContext); + + return ValidateSingleText(vrwArgContext); + } +@@ -140,22 +140,6 @@ + bool + CMICmdArgValString::ValidateSingleText(CMICmdArgContext &vrwArgContext) + { +- if (vrwArgContext.GetNumberArgsPresent() == 1) +- { +- const CMIUtilString &rArg(vrwArgContext.GetArgsLeftToParse()); +- if (IsStringArg(rArg)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = rArg; +- vrwArgContext.RemoveArg(rArg); +- return MIstatus::success; +- } +- else +- return MIstatus::failure; +- } +- +- // More than one option... + const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); + CMIUtilString::VecString_t::const_iterator it = vecOptions.begin(); + while (it != vecOptions.end()) +@@ -168,7 +152,7 @@ + if (vrwArgContext.RemoveArg(rArg)) + { + m_bValid = true; +- m_argValue = rArg; ++ m_argValue = rArg.Unescape(); + return MIstatus::success; + } + else +@@ -184,8 +168,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. Can fall through to +-// ValidateSingleText() or ValidateQuotedQuotedTextEmbedded(). ++// between quotes then delimited by the next space. + // Type: Method. + // Args: vrwArgContext - (RW) The command's argument options string. + // Return: MIstatus::success - Functional succeeded. +@@ -195,44 +178,21 @@ + bool + CMICmdArgValString::ValidateQuotedText(CMICmdArgContext &vrwArgContext) + { +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cQuote = '"'; +- +- // Look for first quote of two +- MIint nPos = strOptions.find(cQuote); +- if (nPos == (MIint)std::string::npos) +- return ValidateSingleText(vrwArgContext); +- +- // Is one and only quote at end of the string +- const MIint nLen = strOptions.length(); +- if (nPos == (MIint)(nLen - 1)) ++ const CMIUtilString::VecString_t vecOptions(vrwArgContext.GetArgs()); ++ if (vecOptions.size() == 0) + return MIstatus::failure; + +- // Quote must be the first character in the string or be preceeded by a space +- if ((nPos > 0) && (strOptions[nPos - 1] != ' ')) ++ const CMIUtilString &rArg(vecOptions[0]); ++ if (!IsStringArg(rArg)) + return MIstatus::failure; + +- // Need to find the other quote +- const MIint nPos2 = strOptions.rfind(cQuote); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; ++ m_bFound = true; + +- // Is there quotes surrounding string formatting embedded quotes +- if (IsStringArgQuotedQuotedTextEmbedded(strOptions)) +- return ValidateQuotedQuotedTextEmbedded(vrwArgContext); +- +- // Make sure not same back quote, need two quotes +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) ++ if (vrwArgContext.RemoveArg(rArg)) + { +- m_bFound = true; + m_bValid = true; +- m_argValue = strOptions.substr(nPos + 1, nPos2 - nPos - 1).c_str(); ++ const MIchar cQuote = '"'; ++ m_argValue = rArg.Trim(cQuote).Unescape(); + return MIstatus::success; + } + +@@ -240,110 +200,6 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". Can fall through to ValidateQuotedText(). +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIchar cBckSlash = '\\'; +- const MIint nPos = strOptions.find(cBckSlash); +- if (nPos == (MIint)std::string::npos) +- return ValidateQuotedText(vrwArgContext); +- +- // Back slash must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Need to find the other back slash +- const MIint nPos2 = strOptions.rfind(cBckSlash); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- // Make sure not same back slash, need two slashs +- if (nPos == nPos2) +- return MIstatus::failure; +- +- // Look for the two quotes +- const MIint nLen = strOptions.length(); +- const MIchar cQuote = '"'; +- const MIint nPosQuote1 = nPos + 1; +- const MIint nPosQuote2 = (nPos2 < nLen) ? nPos2 + 1 : nPos2; +- if ((nPosQuote1 != nPosQuote2) && (strOptions[nPosQuote1] != cQuote) && (strOptions[nPosQuote2] != cQuote)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPosQuote2 - nPos + 1).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ +-// Details: Parse the command's argument options string and try to extract all the words +-// between quotes then delimited by the next space. If there any string format +-// characters '\\' used to embed quotes these are ignored i.e. "\\\"%5d\\\"" +-// becomes "%5d". +-// Type: Method. +-// Args: vrwArgContext - (RW) The command's argument options string. +-// Return: MIstatus::success - Functional succeeded. +-// MIstatus::failure - Functional failed. +-// Throws: None. +-//-- +-bool +-CMICmdArgValString::ValidateQuotedQuotedTextEmbedded(CMICmdArgContext &vrwArgContext) +-{ +- // CODETAG_QUOTEDTEXT_SIMILAR_CODE +- CMIUtilString strOptions = vrwArgContext.GetArgsLeftToParse(); +- const MIint nPos = strOptions.find("\"\\\""); +- if (nPos == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nPos2 = strOptions.rfind("\\\"\""); +- if (nPos2 == (MIint)std::string::npos) +- return MIstatus::failure; +- +- const MIint nLen = strOptions.length(); +- if ((nLen > 5) && ((nPos + 2) == (nPos2 - 2))) +- return MIstatus::failure; +- +- // Quote must be the first character in the string or be preceeded by a space +- // or '\\' +- const MIchar cSpace = ' '; +- if ((nPos > 0) && (strOptions[nPos - 1] != cSpace)) +- return MIstatus::failure; +- +- // Extract quoted text +- const CMIUtilString strQuotedTxt = strOptions.substr(nPos, nPos2 - nPos + 3).c_str(); +- if (vrwArgContext.RemoveArg(strQuotedTxt)) +- { +- m_bFound = true; +- m_bValid = true; +- m_argValue = strQuotedTxt; +- return MIstatus::success; +- } +- +- return MIstatus::failure; +-} +- +-//++ ------------------------------------------------------------------------------------ + // Details: Examine the string and determine if it is a valid string type argument. + // Type: Method. + // Args: vrTxt - (R) Some text. +@@ -373,10 +229,6 @@ + bool + CMICmdArgValString::IsStringArgSingleText(const CMIUtilString &vrTxt) const + { +- // Accept anything as string word +- if (m_bHandleAnything) +- return true; +- + if (!m_bHandleDirPaths) + { + // Look for directory file paths, if found reject +@@ -417,6 +269,10 @@ + bool + CMICmdArgValString::IsStringArgQuotedText(const CMIUtilString &vrTxt) const + { ++ // Accept anything as string word ++ if (m_bHandleAnything) ++ return true; ++ + // CODETAG_QUOTEDTEXT_SIMILAR_CODE + const MIchar cQuote = '"'; + const MIint nPos = vrTxt.find(cQuote); +Index: tools/lldb-mi/MIUtilString.cpp +=================================================================== +--- tools/lldb-mi/MIUtilString.cpp (revision 225612) ++++ tools/lldb-mi/MIUtilString.cpp (working copy) +@@ -221,43 +221,33 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; +- } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) ++ // Find next occurrence of the delimiter after section ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, nSectionPos)); ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; ++ ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); + vwVecSplits.push_back(strSection.c_str()); + ++ // Next ++ nOffset = nNextDelimiterPos + 1; ++ } ++ while (nOffset < nLen); ++ + return vwVecSplits.size(); + } + +@@ -280,83 +270,39 @@ + { + vwVecSplits.clear(); + +- if (this->empty() || vDelimiter.empty()) ++ if (empty() || vDelimiter.empty()) + return 0; + +- MIint nPos = find(vDelimiter); +- if (nPos == (MIint)std::string::npos) ++ const MIuint nLen(length()); ++ MIuint nOffset(0); ++ do + { +- vwVecSplits.push_back(*this); +- return 1; +- } +- const MIint strLen(length()); +- if (nPos == strLen) +- { +- vwVecSplits.push_back(*this); +- return 1; +- } ++ // Find first occurrence which doesn't match to the delimiter ++ const MIuint nSectionPos(FindFirstNot(vDelimiter, nOffset)); ++ if (nSectionPos == (MIuint)std::string::npos) ++ break; + +- // Look for more quotes +- bool bHaveQuotes = false; +- const MIchar cBckSlash = '\\'; +- const MIchar cQuote = '"'; +- MIint nPosQ = find(cQuote); +- MIint nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = nPosQ + 1; +- while (nPosQ2 < strLen) ++ // Find next occurrence of the delimiter after (quoted) section ++ const bool bSkipQuotedText(true); ++ bool bUnmatchedQuote(false); ++ MIuint nNextDelimiterPos(FindFirst(vDelimiter, bSkipQuotedText, bUnmatchedQuote, nSectionPos)); ++ if (bUnmatchedQuote) + { +- nPosQ2 = find(cQuote, nPosQ2); +- if ((nPosQ2 == (MIint)std::string::npos) || (at(nPosQ2 - 1) != cBckSlash)) +- break; +- nPosQ2++; ++ vwVecSplits.clear(); ++ return 0; + } +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } ++ if (nNextDelimiterPos == (MIuint)std::string::npos) ++ nNextDelimiterPos = nLen; + +- MIuint nAdd1(1); +- if ((nPos > 0) && (substr(0, nPos) != vDelimiter)) +- { +- nPos = 0; +- nAdd1 = 0; +- } +- MIint nPos2 = find(vDelimiter, nPos + 1); +- while (nPos2 != (MIint)std::string::npos) +- { +- if (!bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ)))) +- { +- // Extract text or quoted text +- const MIuint len(nPos2 - nPos - nAdd1); +- const std::string strSection(substr(nPos + nAdd1, len)); +- if (strSection != vDelimiter) +- vwVecSplits.push_back(strSection.c_str()); +- nPos += len + 1; +- nPos2 = find(vDelimiter, nPos + 1); +- nAdd1 = 0; ++ // Extract string between delimiters ++ const MIuint nSectionLen(nNextDelimiterPos - nSectionPos); ++ const std::string strSection(substr(nSectionPos, nSectionLen)); ++ vwVecSplits.push_back(strSection.c_str()); + +- if (bHaveQuotes && (nPos2 > nPosQ2)) +- { +- // Reset, look for more quotes +- bHaveQuotes = false; +- nPosQ = find(cQuote, nPos); +- nPosQ2 = (MIint)std::string::npos; +- if (nPosQ != (MIint)std::string::npos) +- { +- nPosQ2 = find(cQuote, nPosQ + 1); +- bHaveQuotes = (nPosQ2 != (MIint)std::string::npos); +- } +- } +- } +- else +- { +- // Skip passed text in quotes +- nPos2 = find(vDelimiter, nPosQ2 + 1); +- } ++ // Next ++ nOffset = nNextDelimiterPos + 1; + } +- const std::string strSection(substr(nPos, strLen - nPos)); +- if ((strSection.length() != 0) && (strSection != vDelimiter)) +- vwVecSplits.push_back(strSection.c_str()); ++ while (nOffset < nLen); + + return vwVecSplits.size(); + } +@@ -696,3 +642,232 @@ + + return true; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ return find(vrPattern, vnPos); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which match to the pattern, but isn't surrounded by quotes. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vbSkipQuotedText - (R) True = don't look at quoted text, false = otherwise. ++// vrwbNotFoundClosedQuote - (W) True = parsing error: unmatched quote, false = otherwise. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first substring that match and which isn't quoted. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos /* = 0 */) const ++{ ++ vrwbNotFoundClosedQuote = false; ++ ++ if (!vbSkipQuotedText) ++ return FindFirst(vrPattern, vnPos); ++ ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nQuotePos(FindFirstQuote(nPos)); ++ const MIuint nPatternPos(FindFirst(vrPattern, nPos)); ++ if (nQuotePos == (MIuint)std::string::npos) ++ return nPatternPos; ++ ++ const MIuint nQuoteClosedPos = FindFirstQuote(nQuotePos + 1); ++ if (nQuoteClosedPos == (MIuint)std::string::npos) ++ { ++ vrwbNotFoundClosedQuote = true; ++ return (MIuint)std::string::npos; ++ } ++ ++ if ((nPatternPos == (MIuint)std::string::npos) || (nPatternPos < nQuotePos)) ++ return nPatternPos; ++ ++ nPos = nQuoteClosedPos + 1; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence in *this string which doesn't match to the pattern. ++// Type: Method. ++// Args: vrPattern - (R) The pattern to search for. ++// vnPos - (R) Position of the first character in the string to be considered in the search. (Dflt = 0) ++// Return: MIuint - The position of the first character that doesn't match. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos /* = 0 */) const ++{ ++ const MIuint nLen(length()); ++ const MIuint nPatternLen(vrPattern.length()); ++ ++ MIuint nPatternPos(vnPos); ++ do ++ { ++ const bool bMatchPattern(compare(nPatternPos, nPatternLen, vrPattern) == 0); ++ if (!bMatchPattern) ++ return nPatternPos; ++ nPatternPos += nPatternLen; ++ } ++ while (nPatternPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Find first occurence of not escaped quotation mark in *this string. ++// Type: Method. ++// Args: vnPos - (R) Position of the first character in the string to be considered in the search. ++// Return: MIuint - The position of the quotation mark. ++// Throws: None. ++//-- ++MIuint ++CMIUtilString::FindFirstQuote(const MIuint vnPos) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIchar cQuote('"'); ++ const MIuint nLen(length()); ++ ++ MIuint nPos = vnPos; ++ do ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nPos)); ++ const MIuint nQuotePos(find(cQuote, nPos)); ++ if ((nBckSlashPos == (MIuint)std::string::npos) || (nQuotePos == (MIuint)std::string::npos)) ++ return nQuotePos; ++ ++ if (nQuotePos < nBckSlashPos) ++ return nQuotePos; ++ ++ // Skip 2 characters: First is '\', second is that which is escaped by '\' ++ nPos = nBckSlashPos + 2; ++ } ++ while (nPos < nLen); ++ ++ return (MIuint)std::string::npos; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: List of characters that should be escaped. ++// Type: Member. ++//-- ++const CMIUtilString CMIUtilString::ms_strEscapeCharacters("`\\\t\n'\""); ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get escaped string from *this string. ++// Type: Method. ++// Args: None. ++// Return: CMIUtilString - The escaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Escape(void) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIuint nLen(length()); ++ std::string strNew; ++ strNew.reserve(nLen); ++ MIuint nOffset(0); ++ while (nOffset < nLen) ++ { ++ const MIuint nEscapeCharPos(find_first_of(ms_strEscapeCharacters, nOffset)); ++ const bool bEscapeCharNotFound(nEscapeCharPos == (MIuint)std::string::npos); ++ if (bEscapeCharNotFound) ++ { ++ const MIuint nAppendAll((MIuint)std::string::npos); ++ strNew.append(*this, nOffset, nAppendAll); ++ break; ++ } ++ const MIuint nAppendLen(nEscapeCharPos - nOffset); ++ strNew.append(*this, nOffset, nAppendLen); ++ strNew.push_back(cBckSlash); ++ const MIchar cUnescapedChar(at(nEscapeCharPos)); ++ switch (cUnescapedChar) ++ { ++ case '\t': ++ strNew.push_back('t'); ++ break; ++ case '\n': ++ strNew.push_back('t'); ++ break; ++ default: ++ strNew.push_back(cUnescapedChar); ++ break; ++ } ++ nOffset = nEscapeCharPos + 1; ++ } ++ return CMIUtilString(strNew.c_str());; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get unescaped string from *this string. ++// Type: Method. ++// Args: None. ++// Return: CMIUtilString - The unescaped version of the initial string. ++// Throws: None. ++//-- ++CMIUtilString ++CMIUtilString::Unescape(void) const ++{ ++ const MIchar cBckSlash('\\'); ++ const MIuint nLen(length()); ++ std::string strNew; ++ strNew.reserve(nLen); ++ MIuint nOffset(0); ++ while (nOffset < nLen) ++ { ++ const MIuint nBckSlashPos(find(cBckSlash, nOffset)); ++ const bool bBckSlashNotFound(nBckSlashPos == (MIuint)std::string::npos); ++ if (bBckSlashNotFound) ++ { ++ const MIuint nAppendAll((MIuint)std::string::npos); ++ strNew.append(*this, nOffset, nAppendAll); ++ break; ++ } ++ const MIuint nAppendLen(nBckSlashPos - nOffset); ++ strNew.append(*this, nOffset, nAppendLen); ++ const bool bBckSlashIsLast(nBckSlashPos == nLen); ++ if (bBckSlashIsLast) ++ { ++ strNew.push_back(cBckSlash); ++ break; ++ } ++ const MIchar cEscapedChar(at(nBckSlashPos + 1)); ++ switch (cEscapedChar) ++ { ++ case 't': ++ strNew.push_back('\t'); ++ break; ++ case 'n': ++ strNew.push_back('\n'); ++ break; ++ default: ++ { ++ const MIuint nEscapedCharPos(ms_strEscapeCharacters.find(cEscapedChar)); ++ const bool bEscapedCharNotLegal(nEscapedCharPos == (MIuint)std::string::npos); ++ if (bEscapedCharNotLegal) ++ strNew.push_back(cBckSlash); ++ strNew.push_back(cEscapedChar); ++ break; ++ } ++ } ++ nOffset = nBckSlashPos + 2; ++ } ++ return CMIUtilString(strNew.c_str());; ++} +Index: tools/lldb-mi/MIUtilString.h +=================================================================== +--- tools/lldb-mi/MIUtilString.h (revision 225612) ++++ tools/lldb-mi/MIUtilString.h (working copy) +@@ -66,6 +66,12 @@ + CMIUtilString StripCRAll(void) const; + CMIUtilString Trim(void) const; + CMIUtilString Trim(const MIchar vChar) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ MIuint FindFirst(const CMIUtilString &vrPattern, const bool vbSkipQuotedText, bool &vrwbNotFoundClosedQuote, ++ const MIuint vnPos = 0) const; ++ MIuint FindFirstNot(const CMIUtilString &vrPattern, const MIuint vnPos = 0) const; ++ CMIUtilString Escape(void) const; ++ CMIUtilString Unescape(void) const; + // + CMIUtilString &operator=(const MIchar *vpRhs); + CMIUtilString &operator=(const std::string &vrRhs); +@@ -82,4 +88,9 @@ + private: + bool ExtractNumberFromHexadecimal(MIint64 &vwrNumber) const; + CMIUtilString RemoveRepeatedCharacters(const MIint vnPos, const MIchar vChar); ++ MIuint FindFirstQuote(const MIuint vnPos) const; ++ ++ // Attributes: ++ private: ++ static const CMIUtilString ms_strEscapeCharacters; + }; Index: patches/lldbmi_fix_segfault_notification.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_segfault_notification.patch @@ -0,0 +1,65 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228328) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -796,6 +796,7 @@ + break; + case lldb::eStopReasonException: + pEventType = "eStopReasonException"; ++ bOk = HandleProcessEventStopException(); + break; + case lldb::eStopReasonExec: + pEventType = "eStopReasonExec"; +@@ -931,6 +932,40 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Asynchronous event handler for LLDB Process stop exception. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException(void) ++{ ++ const lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread sbThread = sbProcess.GetSelectedThread(); ++ const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0); ++ std::shared_ptr spStopDescription(new char[nStopDescriptionLen]); ++ sbThread.GetStopDescription(spStopDescription.get(), nStopDescriptionLen); ++ ++ // MI print "*stopped,reason=\"exception-received\",exception=\"%s\",stopped-threads=\"all\"" ++ const CMICmnMIValueConst miValueConst("exception-received"); ++ const CMICmnMIValueResult miValueResult("reason", miValueConst); ++ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); ++ const CMIUtilString strReason(spStopDescription.get()); ++ const CMICmnMIValueConst miValueConst2(strReason); ++ const CMICmnMIValueResult miValueResult2("exception", miValueConst2); ++ bool bOk = miOutOfBandRecord.Add(miValueResult2); ++ const CMICmnMIValueConst miValueConst3("all"); ++ const CMICmnMIValueResult miValueResult3("stopped-threads", miValueConst3); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult3); ++ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); ++ bOk = bOk && TextToStdout("(gdb)"); ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Form partial MI response in a MI value tuple object. + // Type: Method. + // Args: vwrMiValueTuple - (W) MI value tuple object. +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (revision 228328) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (working copy) +@@ -77,6 +77,7 @@ + bool HandleProcessEventStopReasonTrace(void); + bool HandleProcessEventStopReasonBreakpoint(void); + bool HandleProcessEventStopSignal(bool &vwrbShouldBrk); ++ bool HandleProcessEventStopException(void); + bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent); + bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple); + bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord); Index: patches/lldbmi_fix_segfault_notification.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_segfault_notification.v3.patch @@ -0,0 +1,187 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228573) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -796,6 +796,7 @@ + break; + case lldb::eStopReasonException: + pEventType = "eStopReasonException"; ++ bOk = HandleProcessEventStopException(); + break; + case lldb::eStopReasonExec: + pEventType = "eStopReasonExec"; +@@ -931,6 +932,44 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Asynchronous event handler for LLDB Process stop exception. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException(void) ++{ ++ const lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread sbThread = sbProcess.GetSelectedThread(); ++ const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0); ++ std::shared_ptr spStopDescription(new char[nStopDescriptionLen]); ++ sbThread.GetStopDescription(spStopDescription.get(), nStopDescriptionLen); ++ ++ // MI print "*stopped,reason=\"exception-received\",exception=\"%s\",thread-id=\"%d\",stopped-threads=\"all\"" ++ const CMICmnMIValueConst miValueConst("exception-received"); ++ const CMICmnMIValueResult miValueResult("reason", miValueConst); ++ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); ++ const CMIUtilString strReason(spStopDescription.get()); ++ const CMICmnMIValueConst miValueConst2(strReason); ++ const CMICmnMIValueResult miValueResult2("exception", miValueConst2); ++ bool bOk = miOutOfBandRecord.Add(miValueResult2); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbThread.GetIndexID())); ++ const CMICmnMIValueConst miValueConst3(strThreadId); ++ const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult3); ++ const CMICmnMIValueConst miValueConst4("all"); ++ const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult4); ++ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); ++ bOk = bOk && TextToStdout("(gdb)"); ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Form partial MI response in a MI value tuple object. + // Type: Method. + // Args: vwrMiValueTuple - (W) MI value tuple object. +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (revision 228573) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (working copy) +@@ -77,6 +77,7 @@ + bool HandleProcessEventStopReasonTrace(void); + bool HandleProcessEventStopReasonBreakpoint(void); + bool HandleProcessEventStopSignal(bool &vwrbShouldBrk); ++ bool HandleProcessEventStopException(void); + bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent); + bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple); + bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord); +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 228573) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -112,5 +112,89 @@ + # Clean up + debugserver_child.terminate(force = True) + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stopped_when_segfault_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurs (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set dosegfault=1 and run (to cause a segfault error) ++ self.runCmd("-data-evaluate-expression \"dosegfault=1\"") ++ self.expect("\^done,value=\"1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_segfault_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurs (remote).""" ++ ++ # Prepare debugserver ++ import os, sys ++ lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver")) ++ sys.path.append(lldb_gdbserver_folder) ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ #FIXME -exec-run doesn't work ++ self.runCmd("-interpreter-exec command \"process launch\"") #FIXME: self.runCmd("-exec-run") ++ self.expect("\^done") #FIXME: self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set dosegfault=1 and run (to cause a segfault error) ++ self.runCmd("-data-evaluate-expression \"dosegfault=1\"") ++ self.expect("\^done,value=\"1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ # Exit ++ self.runCmd("-gdb-exit") ++ self.runCmd("") #FIXME lldb-mi hangs here on Linux; extra return is needed ++ self.expect("\^exit") ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 228573) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -12,6 +12,7 @@ + extern int b_MyFunction(); + extern int infloop(); + int doloop; ++int dosegfault; + int g_MyVar = 3; + static int s_MyVar = 4; + int main (int argc, char const *argv[]) +@@ -24,6 +25,11 @@ + //BP_localstest -- it must be at line #24 (or fix it in main*.micmds) + if (doloop) // BP_doloop + infloop(); ++ if (dosegfault) ++ { ++ int *p = NULL; ++ *p = 1; ++ } + if (argc > 1 && *argv[1] == 'l') { + a++; + printf("a=%d, argv[1]=%s\n", a, argv[1]); //BP_argtest Index: patches/lldbmi_fix_segfault_notification.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_segfault_notification.v4.patch @@ -0,0 +1,187 @@ +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228576) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -796,6 +796,7 @@ + break; + case lldb::eStopReasonException: + pEventType = "eStopReasonException"; ++ bOk = HandleProcessEventStopException(); + break; + case lldb::eStopReasonExec: + pEventType = "eStopReasonExec"; +@@ -931,6 +932,44 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Asynchronous event handler for LLDB Process stop exception. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException(void) ++{ ++ const lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread sbThread = sbProcess.GetSelectedThread(); ++ const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0); ++ std::shared_ptr spStopDescription(new char[nStopDescriptionLen]); ++ sbThread.GetStopDescription(spStopDescription.get(), nStopDescriptionLen); ++ ++ // MI print "*stopped,reason=\"exception-received\",exception=\"%s\",thread-id=\"%d\",stopped-threads=\"all\"" ++ const CMICmnMIValueConst miValueConst("exception-received"); ++ const CMICmnMIValueResult miValueResult("reason", miValueConst); ++ CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); ++ const CMIUtilString strReason(spStopDescription.get()); ++ const CMICmnMIValueConst miValueConst2(strReason); ++ const CMICmnMIValueResult miValueResult2("exception", miValueConst2); ++ bool bOk = miOutOfBandRecord.Add(miValueResult2); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbThread.GetIndexID())); ++ const CMICmnMIValueConst miValueConst3(strThreadId); ++ const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult3); ++ const CMICmnMIValueConst miValueConst4("all"); ++ const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4); ++ bOk = bOk && miOutOfBandRecord.Add(miValueResult4); ++ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); ++ bOk = bOk && TextToStdout("(gdb)"); ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Form partial MI response in a MI value tuple object. + // Type: Method. + // Args: vwrMiValueTuple - (W) MI value tuple object. +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (revision 228576) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (working copy) +@@ -77,6 +77,7 @@ + bool HandleProcessEventStopReasonTrace(void); + bool HandleProcessEventStopReasonBreakpoint(void); + bool HandleProcessEventStopSignal(bool &vwrbShouldBrk); ++ bool HandleProcessEventStopException(void); + bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent); + bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple); + bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord); +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 228576) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -112,5 +112,89 @@ + # Clean up + debugserver_child.terminate(force = True) + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stopped_when_segfault_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set dosegfault=1 and run (to cause a segfault error) ++ self.runCmd("-data-evaluate-expression \"dosegfault=1\"") ++ self.expect("\^done,value=\"1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_segfault_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped when segfault occurred (remote).""" ++ ++ # Prepare debugserver ++ import os, sys ++ lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver")) ++ sys.path.append(lldb_gdbserver_folder) ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ #FIXME -exec-run doesn't work ++ self.runCmd("-interpreter-exec command \"process launch\"") #FIXME: self.runCmd("-exec-run") ++ self.expect("\^done") #FIXME: self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set dosegfault=1 and run (to cause a segfault error) ++ self.runCmd("-data-evaluate-expression \"dosegfault=1\"") ++ self.expect("\^done,value=\"1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"exception-received\",exception=\"EXC_BAD_ACCESS \(code=1, address=0x0\)\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ # Exit ++ self.runCmd("-gdb-exit") ++ self.runCmd("") #FIXME lldb-mi hangs here on Linux; extra return is needed ++ self.expect("\^exit") ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 228576) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -12,6 +12,7 @@ + extern int b_MyFunction(); + extern int infloop(); + int doloop; ++int dosegfault; + int g_MyVar = 3; + static int s_MyVar = 4; + int main (int argc, char const *argv[]) +@@ -24,6 +25,11 @@ + //BP_localstest -- it must be at line #24 (or fix it in main*.micmds) + if (doloop) // BP_doloop + infloop(); ++ if (dosegfault) ++ { ++ int *p = NULL; ++ *p = 1; ++ } + if (argc > 1 && *argv[1] == 'l') { + a++; + printf("a=%d, argv[1]=%s\n", a, argv[1]); //BP_argtest Index: patches/lldbmi_fix_sessioninfo_after_CLI_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_sessioninfo_after_CLI_support.patch @@ -0,0 +1,1016 @@ +Index: source/API/SBDebugger.cpp +=================================================================== +--- source/API/SBDebugger.cpp (revision 224992) ++++ source/API/SBDebugger.cpp (working copy) +@@ -1051,6 +1051,7 @@ + if (debugger_sp) + { + ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext()); ++ exe_ctx.SetTargetSP(debugger_sp->GetSelectedTarget()); + error = debugger_sp->SetPropertyValue (&exe_ctx, + eVarSetOperationAssign, + var_name, +@@ -1074,6 +1075,7 @@ + if (debugger_sp) + { + ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext()); ++ exe_ctx.SetTargetSP(debugger_sp->GetSelectedTarget()); + lldb::OptionValueSP value_sp (debugger_sp->GetPropertyValue (&exe_ctx, + var_name, + false, +Index: source/Interpreter/CommandObject.cpp +=================================================================== +--- source/Interpreter/CommandObject.cpp (revision 224992) ++++ source/Interpreter/CommandObject.cpp (working copy) +@@ -199,7 +199,6 @@ + } + + +- + bool + CommandObject::CheckRequirements (CommandReturnObject &result) + { +Index: tools/lldb-mi/MICmdCmdBreak.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdBreak.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdBreak.cpp (working copy) +@@ -232,20 +232,20 @@ + // Ask LLDB to create a breakpoint + bool bOk = MIstatus::success; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + switch (eBrkPtType) + { + case eBreakPoint_ByAddress: +- m_brkPt = rTarget.BreakpointCreateByAddress(nAddress); ++ m_brkPt = sbTarget.BreakpointCreateByAddress(nAddress); + break; + case eBreakPoint_ByFileFn: +- m_brkPt = rTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); ++ m_brkPt = sbTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); + break; + case eBreakPoint_ByFileLine: +- m_brkPt = rTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); ++ m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); + break; + case eBreakPoint_ByName: +- m_brkPt = rTarget.BreakpointCreateByName(m_brkName.c_str(), rTarget.GetExecutable().GetFilename()); ++ m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), sbTarget.GetExecutable().GetFilename()); + break; + case eBreakPoint_count: + case eBreakPoint_NotDefineYet: +@@ -440,7 +440,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const bool bBrkPt = rSessionInfo.m_lldbTarget.BreakpointDelete(static_cast(nBrk)); ++ const bool bBrkPt = rSessionInfo.GetTarget().BreakpointDelete(static_cast(nBrk)); + if (!bBrkPt) + { + const CMIUtilString strBrkNum(CMIUtilString::Format("%d", nBrk)); +@@ -560,7 +560,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtDisabledOk = true; +@@ -700,7 +700,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtEnabledOk = true; +@@ -837,7 +837,7 @@ + m_nBrkPtCount = pArgCount->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetIgnoreCount(m_nBrkPtCount); +@@ -972,7 +972,7 @@ + m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetCondition(m_strBrkPtExpr.c_str()); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -122,8 +122,8 @@ + + const CMIUtilString &rExpression(pArgExpr->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + m_bExpressionValid = (thread.GetNumFrames() > 0); + if (!m_bExpressionValid) + return MIstatus::success; +@@ -410,22 +410,22 @@ + const MIuint nDisasmMode = pArgMode->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + lldb::addr_t lldbStartAddr = static_cast(nAddrStart); +- lldb::SBInstructionList instructions = rTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, rTarget), nAddrEnd - nAddrStart); ++ lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart); + const MIuint nInstructions = instructions.GetSize(); + for (size_t i = 0; i < nInstructions; i++) + { + const MIchar *pUnknown = "??"; + lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i); +- const MIchar *pStrMnemonic = instrt.GetMnemonic(rTarget); ++ const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget); + pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown; + lldb::SBAddress address = instrt.GetAddress(); +- lldb::addr_t addr = address.GetLoadAddress(rTarget); ++ lldb::addr_t addr = address.GetLoadAddress(sbTarget); + const MIchar *pFnName = address.GetFunction().GetName(); + pFnName = (pFnName != nullptr) ? pFnName : pUnknown; + lldb::addr_t addrOffSet = address.GetOffset(); +- const MIchar *pStrOperands = instrt.GetOperands(rTarget); ++ const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" +@@ -599,9 +599,9 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; +- const MIuint64 nReadBytes = rProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); ++ const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); + if (nReadBytes != nAddrNumBytes) + { + SetError( +@@ -827,14 +827,14 @@ + CMICmdCmdDataListRegisterNames::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -906,7 +906,6 @@ + , m_constStrArgFormat("fmt") + , m_constStrArgRegNo("regno") + , m_miValueList(true) +- , m_pProcess(nullptr) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-values"; +@@ -975,13 +974,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } +- m_pProcess = &rProcess; + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +@@ -1051,7 +1049,7 @@ + lldb::SBValue + CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const + { +- lldb::SBThread thread = m_pProcess->GetSelectedThread(); ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -1371,10 +1369,10 @@ + *m_pBufferMemory = static_cast(nValue); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + lldb::addr_t addr = static_cast(m_nAddr + nAddrOffset); +- const size_t nBytesWritten = rProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); ++ const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); + if (nBytesWritten != static_cast(m_nCount)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr)); +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -263,7 +263,6 @@ + const CMIUtilString m_constStrArgFormat; + const CMIUtilString m_constStrArgRegNo; + CMICmnMIValueList m_miValueList; +- lldb::SBProcess *m_pProcess; + }; + + //++ ============================================================================ +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -91,8 +91,8 @@ + lldb::SBError error; + lldb::SBStream errMsg; + uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, +- nullptr, launch_flags, false, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr, ++ nullptr, nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) + { +@@ -100,9 +100,6 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- rSessionInfo.m_lldbProcess = process; +- + if (!CMIDriver::Instance().SetDriverStateRunningDebugging()) + { + const CMIUtilString &rErrMsg(CMIDriver::Instance().GetErrorDescription()); +@@ -137,7 +134,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Give the client '=thread-group-started,id="i1" pid="xyz"' + m_bHasResultRecordExtra = true; + const CMICmnMIValueConst miValueConst2("i1"); +@@ -212,7 +209,7 @@ + { + const MIchar *pCmd = "continue"; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); ++ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); + MIunused(rtn); + + if (m_lldbResult.GetErrorSize() == 0) +@@ -356,7 +353,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -483,7 +480,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-in"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -610,7 +607,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -737,7 +734,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -865,7 +862,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-out"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -962,7 +959,7 @@ + CMICmdCmdExecInterrupt::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("process interrupt"); + const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult, false); + MIunused(status); +Index: tools/lldb-mi/MICmdCmdFile.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdFile.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdFile.cpp (working copy) +@@ -96,7 +96,7 @@ + CMICmdArgValFile *pArgFile = static_cast(pArgNamedFile); + const CMIUtilString &strExeFilePath(pArgFile->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBError error; + const MIchar *pTargetTriple = nullptr; // Let LLDB discover the triple required + const MIchar *pTargetPlatformName = ""; +@@ -137,8 +137,6 @@ + return MIstatus::failure; + } + +- rSessionInfo.m_lldbTarget = target; +- + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmdCmdGdbInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdGdbInfo.cpp (working copy) +@@ -198,11 +198,11 @@ + bool bOk = rStdout.TextToStdout("~\"From To Syms Read Shared Object Library\""); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; +- const MIuint nModules = rTarget.GetNumModules(); ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); ++ const MIuint nModules = sbTarget.GetNumModules(); + for (MIuint i = 0; bOk && (i < nModules); i++) + { +- lldb::SBModule module = rTarget.GetModuleAtIndex(i); ++ lldb::SBModule module = sbTarget.GetModuleAtIndex(i); + if (module.IsValid()) + { + const CMIUtilString strModuleFilePath(module.GetFileSpec().GetDirectory()); +@@ -216,7 +216,7 @@ + for (MIuint j = 0; j < nSections; j++) + { + lldb::SBSection section = module.GetSectionAtIndex(j); +- lldb::addr_t addrLoad = section.GetLoadAddress(rTarget); ++ lldb::addr_t addrLoad = section.GetLoadAddress(sbTarget); + if (addrLoad != (lldb::addr_t) - 1) + { + if (!bHaveAddrLoad) +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Detach(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +@@ -234,17 +234,17 @@ + m_bIsI1 = true; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + +- // Note do not check for rProcess is IsValid(), continue ++ // Note do not check for sbProcess is IsValid(), continue + + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + + if (thread.IsValid()) + { +@@ -292,9 +292,9 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); +@@ -328,20 +328,20 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); + miTuple.Add(miValueResult3); + } + +- if (rSessionInfo.m_lldbTarget.IsValid()) ++ if (rSessionInfo.GetTarget().IsValid()) + { +- lldb::SBTarget &rTrgt = rSessionInfo.m_lldbTarget; +- const MIchar *pDir = rTrgt.GetExecutable().GetDirectory(); +- const MIchar *pFileName = rTrgt.GetExecutable().GetFilename(); ++ lldb::SBTarget sbTrgt = rSessionInfo.GetTarget(); ++ const MIchar *pDir = sbTrgt.GetExecutable().GetDirectory(); ++ const MIchar *pFileName = sbTrgt.GetExecutable().GetFilename(); + const CMIUtilString strFile(CMIUtilString::Format("%s/%s", pDir, pFileName)); + const CMICmnMIValueConst miValueConst4(strFile); + const CMICmnMIValueResult miValueResult4("executable", miValueConst4); +@@ -470,7 +470,7 @@ + const CMIUtilString &rStrCommand(pArgCommand->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + const lldb::ReturnStatus rtn = +- rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); ++ rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -111,8 +111,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadFrames = thread.GetNumFrames(); + + return MIstatus::success; +@@ -237,8 +237,8 @@ + const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + MIuint nThreadFrames = thread.GetNumFrames(); + + // Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg +@@ -414,8 +414,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +@@ -583,8 +583,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdTarget.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdTarget.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdTarget.cpp (working copy) +@@ -100,7 +100,7 @@ + + // Check we have a valid target + // Note: target created via 'file-exec-and-symbols' command +- if (!rSessionInfo.m_lldbTarget.IsValid()) ++ if (!rSessionInfo.GetTarget().IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; +@@ -120,7 +120,7 @@ + // Ask LLDB to collect to the target port + const MIchar *pPlugin("gdb-remote"); + lldb::SBError error; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote(rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error); + + // Verify that we have managed to connect successfully + lldb::SBStream errMsg; +@@ -135,16 +135,11 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents +- // which can fire when interpreting via HandleCommand() below. +- rSessionInfo.m_lldbProcess = process; +- + // Set the environment path if we were given one + CMIUtilString strWkDir; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED), m_cmdData.strMiCmd.c_str(), "target-select")); +@@ -156,7 +151,7 @@ + CMIUtilString strSolibPath; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter(); + + CMIUtilString strCmdString = CMIUtilString::Format("target modules search-paths add . %s", strSolibPath.c_str()); +@@ -190,7 +185,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger + // Give the client '=thread-group-started,id="i1"' + m_bHasResultRecordExtra = true; +Index: tools/lldb-mi/MICmdCmdThread.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdThread.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdThread.cpp (working copy) +@@ -99,12 +99,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + + if (m_bSingleThread) + { +- thread = rProcess.GetThreadByIndexID(nThreadId); ++ thread = sbProcess.GetThreadByIndexID(nThreadId); + m_bThreadInvalid = thread.IsValid(); + if (!m_bThreadInvalid) + return MIstatus::success; +@@ -120,10 +120,10 @@ + + // Multiple threads + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (thread.IsValid()) + { + CMICmnMIValueTuple miTuple; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -170,8 +170,8 @@ + m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetThreadByIndexID(nThreadId); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) +@@ -519,8 +519,8 @@ + vrwbChanged = false; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + if (thread.GetNumFrames() == 0) + { + return MIstatus::success; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -20,13 +20,16 @@ + //-- + + // Third party headers: +-#include ++#include ++#include + #ifdef _WIN32 + #include // For the ::_access() + #else + #include // For the ::access() + #endif // _WIN32 + #include ++#include ++#include + + // In-house headers: + #include "MICmnLLDBDebugSessionInfo.h" +@@ -47,9 +50,7 @@ + // Throws: None. + //-- + CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo(void) +- : m_rLldbDebugger(CMICmnLLDBDebugger::Instance().GetTheDebugger()) +- , m_rLlldbListener(CMICmnLLDBDebugger::Instance().GetTheListener()) +- , m_nBrkPointCntMax(INT32_MAX) ++ : m_nBrkPointCntMax(INT32_MAX) + , m_currentSelectedThread(LLDB_INVALID_THREAD_ID) + , m_constStrSharedDataKeyWkDir("Working Directory") + , m_constStrSharedDataSolibPath("Solib Path") +@@ -226,7 +227,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -299,7 +300,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames2(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -1329,7 +1330,7 @@ + const MIchar *pFn = pUnkwn; + const MIchar *pFilePath = pUnkwn; + size_t nLine = 0; +- const size_t nAddr = brkPtAddr.GetLoadAddress(m_lldbTarget); ++ const size_t nAddr = brkPtAddr.GetLoadAddress(GetTarget()); + + lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit(); + if (rCmplUnit.IsValid()) +@@ -1356,3 +1357,55 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current debugger. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBDebugger - current debugger. ++// Throws: None. ++//-- ++lldb::SBDebugger & ++CMICmnLLDBDebugSessionInfo::GetDebugger() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheDebugger(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current listener. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBListener - current listener. ++// Throws: None. ++//-- ++lldb::SBListener & ++CMICmnLLDBDebugSessionInfo::GetListener() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheListener(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current target. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBTarget - current target. ++// Throws: None. ++//-- ++lldb::SBTarget ++CMICmnLLDBDebugSessionInfo::GetTarget() const ++{ ++ return GetDebugger().GetSelectedTarget(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current process. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBProcess - current process. ++// Throws: None. ++//-- ++lldb::SBProcess ++CMICmnLLDBDebugSessionInfo::GetProcess() const ++{ ++ return GetTarget().GetProcess(); ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -156,14 +156,14 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ lldb::SBDebugger &GetDebugger() const; ++ lldb::SBListener &GetListener() const; ++ lldb::SBTarget GetTarget() const; ++ lldb::SBProcess GetProcess() const; + + // Attributes: + public: + // The following are available to all command instances +- lldb::SBDebugger &m_rLldbDebugger; +- lldb::SBListener &m_rLlldbListener; +- lldb::SBTarget m_lldbTarget; +- lldb::SBProcess m_lldbProcess; + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; +Index: tools/lldb-mi/MICmnLLDBDebugger.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugger.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugger.cpp (working copy) +@@ -148,7 +148,8 @@ + + // Explicitly delete the remote target in case MI needs to exit prematurely otherwise + // LLDB debugger may hang in its Destroy() fn waiting on events +- m_lldbDebugger.DeleteTarget(CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget); ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ m_lldbDebugger.DeleteTarget(sbTarget); + + // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014 + // It appears we need to wait as hang does not occur when hitting a debug breakpoint here +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -722,9 +722,9 @@ + return MIstatus::success; + + bool bOk = MIstatus::success; +- lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBTarget target = rProcess.GetTarget(); ++ lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBTarget target = sbProcess.GetTarget(); + if (rDebugger.GetSelectedTarget() == target) + { + if (!UpdateSelectedThread()) +@@ -768,8 +768,8 @@ + + const MIchar *pEventType = ""; + bool bOk = MIstatus::success; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const lldb::StopReason eStoppedReason = sbProcess.GetSelectedThread().GetStopReason(); + switch (eStoppedReason) + { + case lldb::eStopReasonInvalid: +@@ -828,8 +828,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 nStopReason = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); + switch (nStopReason) + { + case 2: // Terminal interrupt signal. SIGINT +@@ -865,7 +865,7 @@ + const CMICmnMIValueConst miValueConst3("Segmentation fault"); + const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); +- const CMIUtilString strThreadId(CMIUtilString::Format("%d", rProcess.GetSelectedThread().GetIndexID())); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID())); + const CMICmnMIValueConst miValueConst4(strThreadId); + const CMICmnMIValueResult miValueResult4("thread-id", miValueConst4); + bOk = bOk && miOutOfBandRecord.Add(miValueResult4); +@@ -878,12 +878,12 @@ + } + break; + case 19: +- if (rProcess.IsValid()) +- rProcess.Continue(); ++ if (sbProcess.IsValid()) ++ sbProcess.Continue(); + break; + case 5: // Trace/breakpoint trap. SIGTRAP + { +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrames = thread.GetNumFrames(); + if (nFrames > 0) + { +@@ -896,9 +896,9 @@ + + if (CMIUtilString::Compare(threadCloneFn, fnName)) + { +- if (rProcess.IsValid()) ++ if (sbProcess.IsValid()) + { +- rProcess.Continue(); ++ sbProcess.Continue(); + vwrbShouldBrk = true; + break; + } +@@ -939,8 +939,8 @@ + CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple) + { + CMIUtilString strThreadFrame; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -994,9 +994,9 @@ + return MIstatus::failure; + } + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); +- lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex((MIuint)brkPtId); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 brkPtId = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().GetTarget().GetBreakpointAtIndex((MIuint)brkPtId); + + return MiStoppedAtBreakPoint(brkPtId, brkPt); + } +@@ -1015,8 +1015,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1118,8 +1118,8 @@ + CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void) + { + bool bOk = true; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1197,7 +1197,7 @@ + bool + CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread(void) + { +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + if (!process.IsValid()) + return MIstatus::success; + +@@ -1339,7 +1339,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDOUT(&c, 1) > 0) + { + CMIUtilString str; +@@ -1374,7 +1374,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDERR(&c, 1) > 0) + { + CMIUtilString str; +@@ -1448,22 +1448,22 @@ + bool + CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void) + { +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ if (!sbProcess.IsValid()) + return MIstatus::success; +- lldb::SBTarget &rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget; +- if (!rTarget.IsValid()) ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ if (!sbTarget.IsValid()) + return MIstatus::success; + + bool bOk = MIstatus::success; + + // Check for created threads +- const MIuint nThread = rProcess.GetNumThreads(); ++ const MIuint nThread = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThread; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (!thread.IsValid()) + continue; + +@@ -1500,7 +1500,7 @@ + } + } + +- lldb::SBThread currentThread = rProcess.GetSelectedThread(); ++ lldb::SBThread currentThread = sbProcess.GetSelectedThread(); + if (currentThread.IsValid()) + { + const MIuint threadId = currentThread.GetIndexID(); +@@ -1523,7 +1523,7 @@ + while (it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end()) + { + const MIuint nThreadId = *it; +- lldb::SBThread thread = rProcess.GetThreadAtIndex(nThreadId); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(nThreadId); + if (!thread.IsValid()) + { + // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" +Index: tools/lldb-mi/MICmnLLDBProxySBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBProxySBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBProxySBValue.cpp (working copy) +@@ -129,14 +129,14 @@ + return MIstatus::failure; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + MIuint nBufferSize = 64; + bool bNeedResize = false; + MIchar *pBuffer = static_cast(::malloc(nBufferSize)); + do + { + lldb::SBError error; +- const size_t nReadSize = rProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); ++ const size_t nReadSize = sbProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); + if (nReadSize == (nBufferSize - 1)) + { + bNeedResize = true; +Index: tools/lldb-mi/MICmnLLDBUtilSBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (working copy) +@@ -219,7 +219,7 @@ + const MIuint nBytes(128); + const MIchar *pBufferMemory = new MIchar[nBytes]; + lldb::SBError error; +- const MIuint64 nReadBytes = rSessionInfo.m_lldbProcess.ReadMemory(addr, (void *)pBufferMemory, nBytes, error); ++ const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, (void *)pBufferMemory, nBytes, error); + MIunused(nReadBytes); + text = CMIUtilString::Format("\\\"%s\\\"", pBufferMemory); + delete[] pBufferMemory; Index: patches/lldbmi_fix_sessioninfo_after_CLI_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_sessioninfo_after_CLI_support.v2.patch @@ -0,0 +1,1004 @@ +Index: source/API/SBDebugger.cpp +=================================================================== +--- source/API/SBDebugger.cpp (revision 224992) ++++ source/API/SBDebugger.cpp (working copy) +@@ -1051,6 +1051,7 @@ + if (debugger_sp) + { + ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext()); ++ exe_ctx.SetTargetSP(debugger_sp->GetSelectedTarget()); + error = debugger_sp->SetPropertyValue (&exe_ctx, + eVarSetOperationAssign, + var_name, +@@ -1074,6 +1075,7 @@ + if (debugger_sp) + { + ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext()); ++ exe_ctx.SetTargetSP(debugger_sp->GetSelectedTarget()); + lldb::OptionValueSP value_sp (debugger_sp->GetPropertyValue (&exe_ctx, + var_name, + false, +Index: tools/lldb-mi/MICmdCmdBreak.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdBreak.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdBreak.cpp (working copy) +@@ -232,20 +232,20 @@ + // Ask LLDB to create a breakpoint + bool bOk = MIstatus::success; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + switch (eBrkPtType) + { + case eBreakPoint_ByAddress: +- m_brkPt = rTarget.BreakpointCreateByAddress(nAddress); ++ m_brkPt = sbTarget.BreakpointCreateByAddress(nAddress); + break; + case eBreakPoint_ByFileFn: +- m_brkPt = rTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); ++ m_brkPt = sbTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); + break; + case eBreakPoint_ByFileLine: +- m_brkPt = rTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); ++ m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); + break; + case eBreakPoint_ByName: +- m_brkPt = rTarget.BreakpointCreateByName(m_brkName.c_str(), rTarget.GetExecutable().GetFilename()); ++ m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), sbTarget.GetExecutable().GetFilename()); + break; + case eBreakPoint_count: + case eBreakPoint_NotDefineYet: +@@ -440,7 +440,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const bool bBrkPt = rSessionInfo.m_lldbTarget.BreakpointDelete(static_cast(nBrk)); ++ const bool bBrkPt = rSessionInfo.GetTarget().BreakpointDelete(static_cast(nBrk)); + if (!bBrkPt) + { + const CMIUtilString strBrkNum(CMIUtilString::Format("%d", nBrk)); +@@ -560,7 +560,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtDisabledOk = true; +@@ -700,7 +700,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtEnabledOk = true; +@@ -837,7 +837,7 @@ + m_nBrkPtCount = pArgCount->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetIgnoreCount(m_nBrkPtCount); +@@ -972,7 +972,7 @@ + m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetCondition(m_strBrkPtExpr.c_str()); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -122,8 +122,8 @@ + + const CMIUtilString &rExpression(pArgExpr->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + m_bExpressionValid = (thread.GetNumFrames() > 0); + if (!m_bExpressionValid) + return MIstatus::success; +@@ -410,22 +410,22 @@ + const MIuint nDisasmMode = pArgMode->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + lldb::addr_t lldbStartAddr = static_cast(nAddrStart); +- lldb::SBInstructionList instructions = rTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, rTarget), nAddrEnd - nAddrStart); ++ lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart); + const MIuint nInstructions = instructions.GetSize(); + for (size_t i = 0; i < nInstructions; i++) + { + const MIchar *pUnknown = "??"; + lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i); +- const MIchar *pStrMnemonic = instrt.GetMnemonic(rTarget); ++ const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget); + pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown; + lldb::SBAddress address = instrt.GetAddress(); +- lldb::addr_t addr = address.GetLoadAddress(rTarget); ++ lldb::addr_t addr = address.GetLoadAddress(sbTarget); + const MIchar *pFnName = address.GetFunction().GetName(); + pFnName = (pFnName != nullptr) ? pFnName : pUnknown; + lldb::addr_t addrOffSet = address.GetOffset(); +- const MIchar *pStrOperands = instrt.GetOperands(rTarget); ++ const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" +@@ -599,9 +599,9 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; +- const MIuint64 nReadBytes = rProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); ++ const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); + if (nReadBytes != nAddrNumBytes) + { + SetError( +@@ -827,14 +827,14 @@ + CMICmdCmdDataListRegisterNames::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -906,7 +906,6 @@ + , m_constStrArgFormat("fmt") + , m_constStrArgRegNo("regno") + , m_miValueList(true) +- , m_pProcess(nullptr) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-values"; +@@ -975,13 +974,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } +- m_pProcess = &rProcess; + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +@@ -1051,7 +1049,7 @@ + lldb::SBValue + CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const + { +- lldb::SBThread thread = m_pProcess->GetSelectedThread(); ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -1371,10 +1369,10 @@ + *m_pBufferMemory = static_cast(nValue); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + lldb::addr_t addr = static_cast(m_nAddr + nAddrOffset); +- const size_t nBytesWritten = rProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); ++ const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); + if (nBytesWritten != static_cast(m_nCount)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr)); +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -263,7 +263,6 @@ + const CMIUtilString m_constStrArgFormat; + const CMIUtilString m_constStrArgRegNo; + CMICmnMIValueList m_miValueList; +- lldb::SBProcess *m_pProcess; + }; + + //++ ============================================================================ +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -91,8 +91,8 @@ + lldb::SBError error; + lldb::SBStream errMsg; + uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, +- nullptr, launch_flags, false, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr, ++ nullptr, nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) + { +@@ -100,9 +100,6 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- rSessionInfo.m_lldbProcess = process; +- + if (!CMIDriver::Instance().SetDriverStateRunningDebugging()) + { + const CMIUtilString &rErrMsg(CMIDriver::Instance().GetErrorDescription()); +@@ -137,7 +134,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Give the client '=thread-group-started,id="i1" pid="xyz"' + m_bHasResultRecordExtra = true; + const CMICmnMIValueConst miValueConst2("i1"); +@@ -212,7 +209,7 @@ + { + const MIchar *pCmd = "continue"; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); ++ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); + MIunused(rtn); + + if (m_lldbResult.GetErrorSize() == 0) +@@ -356,7 +353,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -483,7 +480,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-in"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -610,7 +607,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -737,7 +734,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -865,7 +862,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-out"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -962,7 +959,7 @@ + CMICmdCmdExecInterrupt::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("process interrupt"); + const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult, false); + MIunused(status); +Index: tools/lldb-mi/MICmdCmdFile.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdFile.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdFile.cpp (working copy) +@@ -96,7 +96,7 @@ + CMICmdArgValFile *pArgFile = static_cast(pArgNamedFile); + const CMIUtilString &strExeFilePath(pArgFile->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBError error; + const MIchar *pTargetTriple = nullptr; // Let LLDB discover the triple required + const MIchar *pTargetPlatformName = ""; +@@ -137,8 +137,6 @@ + return MIstatus::failure; + } + +- rSessionInfo.m_lldbTarget = target; +- + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmdCmdGdbInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdGdbInfo.cpp (working copy) +@@ -198,11 +198,11 @@ + bool bOk = rStdout.TextToStdout("~\"From To Syms Read Shared Object Library\""); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; +- const MIuint nModules = rTarget.GetNumModules(); ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); ++ const MIuint nModules = sbTarget.GetNumModules(); + for (MIuint i = 0; bOk && (i < nModules); i++) + { +- lldb::SBModule module = rTarget.GetModuleAtIndex(i); ++ lldb::SBModule module = sbTarget.GetModuleAtIndex(i); + if (module.IsValid()) + { + const CMIUtilString strModuleFilePath(module.GetFileSpec().GetDirectory()); +@@ -216,7 +216,7 @@ + for (MIuint j = 0; j < nSections; j++) + { + lldb::SBSection section = module.GetSectionAtIndex(j); +- lldb::addr_t addrLoad = section.GetLoadAddress(rTarget); ++ lldb::addr_t addrLoad = section.GetLoadAddress(sbTarget); + if (addrLoad != (lldb::addr_t) - 1) + { + if (!bHaveAddrLoad) +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Detach(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +@@ -234,17 +234,17 @@ + m_bIsI1 = true; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + +- // Note do not check for rProcess is IsValid(), continue ++ // Note do not check for sbProcess is IsValid(), continue + + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + + if (thread.IsValid()) + { +@@ -292,9 +292,9 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); +@@ -328,20 +328,20 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); + miTuple.Add(miValueResult3); + } + +- if (rSessionInfo.m_lldbTarget.IsValid()) ++ if (rSessionInfo.GetTarget().IsValid()) + { +- lldb::SBTarget &rTrgt = rSessionInfo.m_lldbTarget; +- const MIchar *pDir = rTrgt.GetExecutable().GetDirectory(); +- const MIchar *pFileName = rTrgt.GetExecutable().GetFilename(); ++ lldb::SBTarget sbTrgt = rSessionInfo.GetTarget(); ++ const MIchar *pDir = sbTrgt.GetExecutable().GetDirectory(); ++ const MIchar *pFileName = sbTrgt.GetExecutable().GetFilename(); + const CMIUtilString strFile(CMIUtilString::Format("%s/%s", pDir, pFileName)); + const CMICmnMIValueConst miValueConst4(strFile); + const CMICmnMIValueResult miValueResult4("executable", miValueConst4); +@@ -470,7 +470,7 @@ + const CMIUtilString &rStrCommand(pArgCommand->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + const lldb::ReturnStatus rtn = +- rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); ++ rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -111,8 +111,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadFrames = thread.GetNumFrames(); + + return MIstatus::success; +@@ -237,8 +237,8 @@ + const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + MIuint nThreadFrames = thread.GetNumFrames(); + + // Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg +@@ -414,8 +414,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +@@ -583,8 +583,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdTarget.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdTarget.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdTarget.cpp (working copy) +@@ -100,7 +100,7 @@ + + // Check we have a valid target + // Note: target created via 'file-exec-and-symbols' command +- if (!rSessionInfo.m_lldbTarget.IsValid()) ++ if (!rSessionInfo.GetTarget().IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; +@@ -120,7 +120,7 @@ + // Ask LLDB to collect to the target port + const MIchar *pPlugin("gdb-remote"); + lldb::SBError error; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote(rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error); + + // Verify that we have managed to connect successfully + lldb::SBStream errMsg; +@@ -135,16 +135,11 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents +- // which can fire when interpreting via HandleCommand() below. +- rSessionInfo.m_lldbProcess = process; +- + // Set the environment path if we were given one + CMIUtilString strWkDir; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED), m_cmdData.strMiCmd.c_str(), "target-select")); +@@ -156,7 +151,7 @@ + CMIUtilString strSolibPath; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter(); + + CMIUtilString strCmdString = CMIUtilString::Format("target modules search-paths add . %s", strSolibPath.c_str()); +@@ -190,7 +185,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger + // Give the client '=thread-group-started,id="i1"' + m_bHasResultRecordExtra = true; +Index: tools/lldb-mi/MICmdCmdThread.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdThread.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdThread.cpp (working copy) +@@ -99,12 +99,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + + if (m_bSingleThread) + { +- thread = rProcess.GetThreadByIndexID(nThreadId); ++ thread = sbProcess.GetThreadByIndexID(nThreadId); + m_bThreadInvalid = thread.IsValid(); + if (!m_bThreadInvalid) + return MIstatus::success; +@@ -120,10 +120,10 @@ + + // Multiple threads + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (thread.IsValid()) + { + CMICmnMIValueTuple miTuple; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -170,8 +170,8 @@ + m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetThreadByIndexID(nThreadId); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) +@@ -519,8 +519,8 @@ + vrwbChanged = false; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + if (thread.GetNumFrames() == 0) + { + return MIstatus::success; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -20,13 +20,16 @@ + //-- + + // Third party headers: +-#include ++#include ++#include + #ifdef _WIN32 + #include // For the ::_access() + #else + #include // For the ::access() + #endif // _WIN32 + #include ++#include ++#include + + // In-house headers: + #include "MICmnLLDBDebugSessionInfo.h" +@@ -47,9 +50,7 @@ + // Throws: None. + //-- + CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo(void) +- : m_rLldbDebugger(CMICmnLLDBDebugger::Instance().GetTheDebugger()) +- , m_rLlldbListener(CMICmnLLDBDebugger::Instance().GetTheListener()) +- , m_nBrkPointCntMax(INT32_MAX) ++ : m_nBrkPointCntMax(INT32_MAX) + , m_currentSelectedThread(LLDB_INVALID_THREAD_ID) + , m_constStrSharedDataKeyWkDir("Working Directory") + , m_constStrSharedDataSolibPath("Solib Path") +@@ -226,7 +227,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -299,7 +300,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames2(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -1329,7 +1330,7 @@ + const MIchar *pFn = pUnkwn; + const MIchar *pFilePath = pUnkwn; + size_t nLine = 0; +- const size_t nAddr = brkPtAddr.GetLoadAddress(m_lldbTarget); ++ const size_t nAddr = brkPtAddr.GetLoadAddress(GetTarget()); + + lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit(); + if (rCmplUnit.IsValid()) +@@ -1356,3 +1357,55 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current debugger. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBDebugger - current debugger. ++// Throws: None. ++//-- ++lldb::SBDebugger & ++CMICmnLLDBDebugSessionInfo::GetDebugger() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheDebugger(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current listener. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBListener - current listener. ++// Throws: None. ++//-- ++lldb::SBListener & ++CMICmnLLDBDebugSessionInfo::GetListener() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheListener(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current target. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBTarget - current target. ++// Throws: None. ++//-- ++lldb::SBTarget ++CMICmnLLDBDebugSessionInfo::GetTarget() const ++{ ++ return GetDebugger().GetSelectedTarget(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current process. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBProcess - current process. ++// Throws: None. ++//-- ++lldb::SBProcess ++CMICmnLLDBDebugSessionInfo::GetProcess() const ++{ ++ return GetTarget().GetProcess(); ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -156,14 +156,14 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ lldb::SBDebugger &GetDebugger() const; ++ lldb::SBListener &GetListener() const; ++ lldb::SBTarget GetTarget() const; ++ lldb::SBProcess GetProcess() const; + + // Attributes: + public: + // The following are available to all command instances +- lldb::SBDebugger &m_rLldbDebugger; +- lldb::SBListener &m_rLlldbListener; +- lldb::SBTarget m_lldbTarget; +- lldb::SBProcess m_lldbProcess; + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; +Index: tools/lldb-mi/MICmnLLDBDebugger.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugger.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugger.cpp (working copy) +@@ -148,7 +148,8 @@ + + // Explicitly delete the remote target in case MI needs to exit prematurely otherwise + // LLDB debugger may hang in its Destroy() fn waiting on events +- m_lldbDebugger.DeleteTarget(CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget); ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ m_lldbDebugger.DeleteTarget(sbTarget); + + // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014 + // It appears we need to wait as hang does not occur when hitting a debug breakpoint here +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -722,9 +722,9 @@ + return MIstatus::success; + + bool bOk = MIstatus::success; +- lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBTarget target = rProcess.GetTarget(); ++ lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBTarget target = sbProcess.GetTarget(); + if (rDebugger.GetSelectedTarget() == target) + { + if (!UpdateSelectedThread()) +@@ -768,8 +768,8 @@ + + const MIchar *pEventType = ""; + bool bOk = MIstatus::success; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const lldb::StopReason eStoppedReason = sbProcess.GetSelectedThread().GetStopReason(); + switch (eStoppedReason) + { + case lldb::eStopReasonInvalid: +@@ -828,8 +828,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 nStopReason = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); + switch (nStopReason) + { + case 2: // Terminal interrupt signal. SIGINT +@@ -865,7 +865,7 @@ + const CMICmnMIValueConst miValueConst3("Segmentation fault"); + const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); +- const CMIUtilString strThreadId(CMIUtilString::Format("%d", rProcess.GetSelectedThread().GetIndexID())); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID())); + const CMICmnMIValueConst miValueConst4(strThreadId); + const CMICmnMIValueResult miValueResult4("thread-id", miValueConst4); + bOk = bOk && miOutOfBandRecord.Add(miValueResult4); +@@ -878,12 +878,12 @@ + } + break; + case 19: +- if (rProcess.IsValid()) +- rProcess.Continue(); ++ if (sbProcess.IsValid()) ++ sbProcess.Continue(); + break; + case 5: // Trace/breakpoint trap. SIGTRAP + { +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrames = thread.GetNumFrames(); + if (nFrames > 0) + { +@@ -896,9 +896,9 @@ + + if (CMIUtilString::Compare(threadCloneFn, fnName)) + { +- if (rProcess.IsValid()) ++ if (sbProcess.IsValid()) + { +- rProcess.Continue(); ++ sbProcess.Continue(); + vwrbShouldBrk = true; + break; + } +@@ -939,8 +939,8 @@ + CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple) + { + CMIUtilString strThreadFrame; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -994,9 +994,9 @@ + return MIstatus::failure; + } + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); +- lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex((MIuint)brkPtId); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 brkPtId = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().GetTarget().GetBreakpointAtIndex((MIuint)brkPtId); + + return MiStoppedAtBreakPoint(brkPtId, brkPt); + } +@@ -1015,8 +1015,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1118,8 +1118,8 @@ + CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void) + { + bool bOk = true; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1197,7 +1197,7 @@ + bool + CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread(void) + { +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + if (!process.IsValid()) + return MIstatus::success; + +@@ -1339,7 +1339,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDOUT(&c, 1) > 0) + { + CMIUtilString str; +@@ -1374,7 +1374,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDERR(&c, 1) > 0) + { + CMIUtilString str; +@@ -1448,22 +1448,22 @@ + bool + CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void) + { +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ if (!sbProcess.IsValid()) + return MIstatus::success; +- lldb::SBTarget &rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget; +- if (!rTarget.IsValid()) ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ if (!sbTarget.IsValid()) + return MIstatus::success; + + bool bOk = MIstatus::success; + + // Check for created threads +- const MIuint nThread = rProcess.GetNumThreads(); ++ const MIuint nThread = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThread; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (!thread.IsValid()) + continue; + +@@ -1500,7 +1500,7 @@ + } + } + +- lldb::SBThread currentThread = rProcess.GetSelectedThread(); ++ lldb::SBThread currentThread = sbProcess.GetSelectedThread(); + if (currentThread.IsValid()) + { + const MIuint threadId = currentThread.GetIndexID(); +@@ -1523,7 +1523,7 @@ + while (it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end()) + { + const MIuint nThreadId = *it; +- lldb::SBThread thread = rProcess.GetThreadAtIndex(nThreadId); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(nThreadId); + if (!thread.IsValid()) + { + // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" +Index: tools/lldb-mi/MICmnLLDBProxySBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBProxySBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBProxySBValue.cpp (working copy) +@@ -129,14 +129,14 @@ + return MIstatus::failure; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + MIuint nBufferSize = 64; + bool bNeedResize = false; + MIchar *pBuffer = static_cast(::malloc(nBufferSize)); + do + { + lldb::SBError error; +- const size_t nReadSize = rProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); ++ const size_t nReadSize = sbProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); + if (nReadSize == (nBufferSize - 1)) + { + bNeedResize = true; +Index: tools/lldb-mi/MICmnLLDBUtilSBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (working copy) +@@ -219,7 +219,7 @@ + const MIuint nBytes(128); + const MIchar *pBufferMemory = new MIchar[nBytes]; + lldb::SBError error; +- const MIuint64 nReadBytes = rSessionInfo.m_lldbProcess.ReadMemory(addr, (void *)pBufferMemory, nBytes, error); ++ const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, (void *)pBufferMemory, nBytes, error); + MIunused(nReadBytes); + text = CMIUtilString::Format("\\\"%s\\\"", pBufferMemory); + delete[] pBufferMemory; Index: patches/lldbmi_fix_sessioninfo_after_CLI_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_sessioninfo_after_CLI_support.v3.patch @@ -0,0 +1,984 @@ +Index: tools/lldb-mi/MICmdCmdBreak.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdBreak.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdBreak.cpp (working copy) +@@ -232,20 +232,20 @@ + // Ask LLDB to create a breakpoint + bool bOk = MIstatus::success; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + switch (eBrkPtType) + { + case eBreakPoint_ByAddress: +- m_brkPt = rTarget.BreakpointCreateByAddress(nAddress); ++ m_brkPt = sbTarget.BreakpointCreateByAddress(nAddress); + break; + case eBreakPoint_ByFileFn: +- m_brkPt = rTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); ++ m_brkPt = sbTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); + break; + case eBreakPoint_ByFileLine: +- m_brkPt = rTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); ++ m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); + break; + case eBreakPoint_ByName: +- m_brkPt = rTarget.BreakpointCreateByName(m_brkName.c_str(), rTarget.GetExecutable().GetFilename()); ++ m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), sbTarget.GetExecutable().GetFilename()); + break; + case eBreakPoint_count: + case eBreakPoint_NotDefineYet: +@@ -440,7 +440,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const bool bBrkPt = rSessionInfo.m_lldbTarget.BreakpointDelete(static_cast(nBrk)); ++ const bool bBrkPt = rSessionInfo.GetTarget().BreakpointDelete(static_cast(nBrk)); + if (!bBrkPt) + { + const CMIUtilString strBrkNum(CMIUtilString::Format("%d", nBrk)); +@@ -560,7 +560,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtDisabledOk = true; +@@ -700,7 +700,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtEnabledOk = true; +@@ -837,7 +837,7 @@ + m_nBrkPtCount = pArgCount->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetIgnoreCount(m_nBrkPtCount); +@@ -972,7 +972,7 @@ + m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetCondition(m_strBrkPtExpr.c_str()); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -122,8 +122,8 @@ + + const CMIUtilString &rExpression(pArgExpr->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + m_bExpressionValid = (thread.GetNumFrames() > 0); + if (!m_bExpressionValid) + return MIstatus::success; +@@ -410,22 +410,22 @@ + const MIuint nDisasmMode = pArgMode->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + lldb::addr_t lldbStartAddr = static_cast(nAddrStart); +- lldb::SBInstructionList instructions = rTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, rTarget), nAddrEnd - nAddrStart); ++ lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart); + const MIuint nInstructions = instructions.GetSize(); + for (size_t i = 0; i < nInstructions; i++) + { + const MIchar *pUnknown = "??"; + lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i); +- const MIchar *pStrMnemonic = instrt.GetMnemonic(rTarget); ++ const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget); + pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown; + lldb::SBAddress address = instrt.GetAddress(); +- lldb::addr_t addr = address.GetLoadAddress(rTarget); ++ lldb::addr_t addr = address.GetLoadAddress(sbTarget); + const MIchar *pFnName = address.GetFunction().GetName(); + pFnName = (pFnName != nullptr) ? pFnName : pUnknown; + lldb::addr_t addrOffSet = address.GetOffset(); +- const MIchar *pStrOperands = instrt.GetOperands(rTarget); ++ const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" +@@ -599,9 +599,9 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; +- const MIuint64 nReadBytes = rProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); ++ const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); + if (nReadBytes != nAddrNumBytes) + { + SetError( +@@ -827,14 +827,14 @@ + CMICmdCmdDataListRegisterNames::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -906,7 +906,6 @@ + , m_constStrArgFormat("fmt") + , m_constStrArgRegNo("regno") + , m_miValueList(true) +- , m_pProcess(nullptr) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-values"; +@@ -975,13 +974,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } +- m_pProcess = &rProcess; + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +@@ -1051,7 +1049,7 @@ + lldb::SBValue + CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const + { +- lldb::SBThread thread = m_pProcess->GetSelectedThread(); ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -1371,10 +1369,10 @@ + *m_pBufferMemory = static_cast(nValue); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + lldb::addr_t addr = static_cast(m_nAddr + nAddrOffset); +- const size_t nBytesWritten = rProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); ++ const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); + if (nBytesWritten != static_cast(m_nCount)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr)); +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 224992) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -263,7 +263,6 @@ + const CMIUtilString m_constStrArgFormat; + const CMIUtilString m_constStrArgRegNo; + CMICmnMIValueList m_miValueList; +- lldb::SBProcess *m_pProcess; + }; + + //++ ============================================================================ +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -91,8 +91,8 @@ + lldb::SBError error; + lldb::SBStream errMsg; + uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, +- nullptr, launch_flags, false, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr, ++ nullptr, nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) + { +@@ -100,9 +100,6 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- rSessionInfo.m_lldbProcess = process; +- + if (!CMIDriver::Instance().SetDriverStateRunningDebugging()) + { + const CMIUtilString &rErrMsg(CMIDriver::Instance().GetErrorDescription()); +@@ -137,7 +134,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Give the client '=thread-group-started,id="i1" pid="xyz"' + m_bHasResultRecordExtra = true; + const CMICmnMIValueConst miValueConst2("i1"); +@@ -212,7 +209,7 @@ + { + const MIchar *pCmd = "continue"; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); ++ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); + MIunused(rtn); + + if (m_lldbResult.GetErrorSize() == 0) +@@ -356,7 +353,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -483,7 +480,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-in"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -610,7 +607,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -737,7 +734,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -865,7 +862,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-out"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -962,7 +959,7 @@ + CMICmdCmdExecInterrupt::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("process interrupt"); + const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult, false); + MIunused(status); +Index: tools/lldb-mi/MICmdCmdFile.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdFile.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdFile.cpp (working copy) +@@ -96,7 +96,7 @@ + CMICmdArgValFile *pArgFile = static_cast(pArgNamedFile); + const CMIUtilString &strExeFilePath(pArgFile->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBError error; + const MIchar *pTargetTriple = nullptr; // Let LLDB discover the triple required + const MIchar *pTargetPlatformName = ""; +@@ -137,8 +137,6 @@ + return MIstatus::failure; + } + +- rSessionInfo.m_lldbTarget = target; +- + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmdCmdGdbInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdGdbInfo.cpp (working copy) +@@ -198,11 +198,11 @@ + bool bOk = rStdout.TextToStdout("~\"From To Syms Read Shared Object Library\""); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; +- const MIuint nModules = rTarget.GetNumModules(); ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); ++ const MIuint nModules = sbTarget.GetNumModules(); + for (MIuint i = 0; bOk && (i < nModules); i++) + { +- lldb::SBModule module = rTarget.GetModuleAtIndex(i); ++ lldb::SBModule module = sbTarget.GetModuleAtIndex(i); + if (module.IsValid()) + { + const CMIUtilString strModuleFilePath(module.GetFileSpec().GetDirectory()); +@@ -216,7 +216,7 @@ + for (MIuint j = 0; j < nSections; j++) + { + lldb::SBSection section = module.GetSectionAtIndex(j); +- lldb::addr_t addrLoad = section.GetLoadAddress(rTarget); ++ lldb::addr_t addrLoad = section.GetLoadAddress(sbTarget); + if (addrLoad != (lldb::addr_t) - 1) + { + if (!bHaveAddrLoad) +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Detach(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +@@ -234,17 +234,17 @@ + m_bIsI1 = true; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + +- // Note do not check for rProcess is IsValid(), continue ++ // Note do not check for sbProcess is IsValid(), continue + + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + + if (thread.IsValid()) + { +@@ -292,9 +292,9 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); +@@ -328,20 +328,20 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); + miTuple.Add(miValueResult3); + } + +- if (rSessionInfo.m_lldbTarget.IsValid()) ++ if (rSessionInfo.GetTarget().IsValid()) + { +- lldb::SBTarget &rTrgt = rSessionInfo.m_lldbTarget; +- const MIchar *pDir = rTrgt.GetExecutable().GetDirectory(); +- const MIchar *pFileName = rTrgt.GetExecutable().GetFilename(); ++ lldb::SBTarget sbTrgt = rSessionInfo.GetTarget(); ++ const MIchar *pDir = sbTrgt.GetExecutable().GetDirectory(); ++ const MIchar *pFileName = sbTrgt.GetExecutable().GetFilename(); + const CMIUtilString strFile(CMIUtilString::Format("%s/%s", pDir, pFileName)); + const CMICmnMIValueConst miValueConst4(strFile); + const CMICmnMIValueResult miValueResult4("executable", miValueConst4); +@@ -470,7 +470,7 @@ + const CMIUtilString &rStrCommand(pArgCommand->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + const lldb::ReturnStatus rtn = +- rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); ++ rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -111,8 +111,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadFrames = thread.GetNumFrames(); + + return MIstatus::success; +@@ -237,8 +237,8 @@ + const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + MIuint nThreadFrames = thread.GetNumFrames(); + + // Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg +@@ -414,8 +414,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +@@ -583,8 +583,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdTarget.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdTarget.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdTarget.cpp (working copy) +@@ -100,7 +100,7 @@ + + // Check we have a valid target + // Note: target created via 'file-exec-and-symbols' command +- if (!rSessionInfo.m_lldbTarget.IsValid()) ++ if (!rSessionInfo.GetTarget().IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; +@@ -120,7 +120,7 @@ + // Ask LLDB to collect to the target port + const MIchar *pPlugin("gdb-remote"); + lldb::SBError error; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote(rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error); + + // Verify that we have managed to connect successfully + lldb::SBStream errMsg; +@@ -135,16 +135,11 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents +- // which can fire when interpreting via HandleCommand() below. +- rSessionInfo.m_lldbProcess = process; +- + // Set the environment path if we were given one + CMIUtilString strWkDir; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED), m_cmdData.strMiCmd.c_str(), "target-select")); +@@ -156,7 +151,7 @@ + CMIUtilString strSolibPath; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter(); + + CMIUtilString strCmdString = CMIUtilString::Format("target modules search-paths add . %s", strSolibPath.c_str()); +@@ -190,7 +185,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger + // Give the client '=thread-group-started,id="i1"' + m_bHasResultRecordExtra = true; +Index: tools/lldb-mi/MICmdCmdThread.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdThread.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdThread.cpp (working copy) +@@ -99,12 +99,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + + if (m_bSingleThread) + { +- thread = rProcess.GetThreadByIndexID(nThreadId); ++ thread = sbProcess.GetThreadByIndexID(nThreadId); + m_bThreadInvalid = thread.IsValid(); + if (!m_bThreadInvalid) + return MIstatus::success; +@@ -120,10 +120,10 @@ + + // Multiple threads + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (thread.IsValid()) + { + CMICmnMIValueTuple miTuple; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 224992) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -170,8 +170,8 @@ + m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetThreadByIndexID(nThreadId); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetThreadByIndexID(nThreadId); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); + if (!value.IsValid()) +@@ -519,8 +519,8 @@ + vrwbChanged = false; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + if (thread.GetNumFrames() == 0) + { + return MIstatus::success; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -20,13 +20,16 @@ + //-- + + // Third party headers: +-#include ++#include ++#include + #ifdef _WIN32 + #include // For the ::_access() + #else + #include // For the ::access() + #endif // _WIN32 + #include ++#include ++#include + + // In-house headers: + #include "MICmnLLDBDebugSessionInfo.h" +@@ -47,9 +50,7 @@ + // Throws: None. + //-- + CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo(void) +- : m_rLldbDebugger(CMICmnLLDBDebugger::Instance().GetTheDebugger()) +- , m_rLlldbListener(CMICmnLLDBDebugger::Instance().GetTheListener()) +- , m_nBrkPointCntMax(INT32_MAX) ++ : m_nBrkPointCntMax(INT32_MAX) + , m_currentSelectedThread(LLDB_INVALID_THREAD_ID) + , m_constStrSharedDataKeyWkDir("Working Directory") + , m_constStrSharedDataSolibPath("Solib Path") +@@ -226,7 +227,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -299,7 +300,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames2(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -1329,7 +1330,7 @@ + const MIchar *pFn = pUnkwn; + const MIchar *pFilePath = pUnkwn; + size_t nLine = 0; +- const size_t nAddr = brkPtAddr.GetLoadAddress(m_lldbTarget); ++ const size_t nAddr = brkPtAddr.GetLoadAddress(GetTarget()); + + lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit(); + if (rCmplUnit.IsValid()) +@@ -1356,3 +1357,55 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current debugger. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBDebugger - current debugger. ++// Throws: None. ++//-- ++lldb::SBDebugger & ++CMICmnLLDBDebugSessionInfo::GetDebugger() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheDebugger(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current listener. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBListener - current listener. ++// Throws: None. ++//-- ++lldb::SBListener & ++CMICmnLLDBDebugSessionInfo::GetListener() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheListener(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current target. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBTarget - current target. ++// Throws: None. ++//-- ++lldb::SBTarget ++CMICmnLLDBDebugSessionInfo::GetTarget() const ++{ ++ return GetDebugger().GetSelectedTarget(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current process. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBProcess - current process. ++// Throws: None. ++//-- ++lldb::SBProcess ++CMICmnLLDBDebugSessionInfo::GetProcess() const ++{ ++ return GetTarget().GetProcess(); ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -156,14 +156,14 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ lldb::SBDebugger &GetDebugger() const; ++ lldb::SBListener &GetListener() const; ++ lldb::SBTarget GetTarget() const; ++ lldb::SBProcess GetProcess() const; + + // Attributes: + public: + // The following are available to all command instances +- lldb::SBDebugger &m_rLldbDebugger; +- lldb::SBListener &m_rLlldbListener; +- lldb::SBTarget m_lldbTarget; +- lldb::SBProcess m_lldbProcess; + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; +Index: tools/lldb-mi/MICmnLLDBDebugger.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugger.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebugger.cpp (working copy) +@@ -148,7 +148,8 @@ + + // Explicitly delete the remote target in case MI needs to exit prematurely otherwise + // LLDB debugger may hang in its Destroy() fn waiting on events +- m_lldbDebugger.DeleteTarget(CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget); ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ m_lldbDebugger.DeleteTarget(sbTarget); + + // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014 + // It appears we need to wait as hang does not occur when hitting a debug breakpoint here +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -722,9 +722,9 @@ + return MIstatus::success; + + bool bOk = MIstatus::success; +- lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBTarget target = rProcess.GetTarget(); ++ lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBTarget target = sbProcess.GetTarget(); + if (rDebugger.GetSelectedTarget() == target) + { + if (!UpdateSelectedThread()) +@@ -768,8 +768,8 @@ + + const MIchar *pEventType = ""; + bool bOk = MIstatus::success; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const lldb::StopReason eStoppedReason = sbProcess.GetSelectedThread().GetStopReason(); + switch (eStoppedReason) + { + case lldb::eStopReasonInvalid: +@@ -828,8 +828,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 nStopReason = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); + switch (nStopReason) + { + case 2: // Terminal interrupt signal. SIGINT +@@ -865,7 +865,7 @@ + const CMICmnMIValueConst miValueConst3("Segmentation fault"); + const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); +- const CMIUtilString strThreadId(CMIUtilString::Format("%d", rProcess.GetSelectedThread().GetIndexID())); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID())); + const CMICmnMIValueConst miValueConst4(strThreadId); + const CMICmnMIValueResult miValueResult4("thread-id", miValueConst4); + bOk = bOk && miOutOfBandRecord.Add(miValueResult4); +@@ -878,12 +878,12 @@ + } + break; + case 19: +- if (rProcess.IsValid()) +- rProcess.Continue(); ++ if (sbProcess.IsValid()) ++ sbProcess.Continue(); + break; + case 5: // Trace/breakpoint trap. SIGTRAP + { +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrames = thread.GetNumFrames(); + if (nFrames > 0) + { +@@ -896,9 +896,9 @@ + + if (CMIUtilString::Compare(threadCloneFn, fnName)) + { +- if (rProcess.IsValid()) ++ if (sbProcess.IsValid()) + { +- rProcess.Continue(); ++ sbProcess.Continue(); + vwrbShouldBrk = true; + break; + } +@@ -939,8 +939,8 @@ + CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple) + { + CMIUtilString strThreadFrame; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -994,9 +994,9 @@ + return MIstatus::failure; + } + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); +- lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex((MIuint)brkPtId); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 brkPtId = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().GetTarget().GetBreakpointAtIndex((MIuint)brkPtId); + + return MiStoppedAtBreakPoint(brkPtId, brkPt); + } +@@ -1015,8 +1015,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1118,8 +1118,8 @@ + CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void) + { + bool bOk = true; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1197,7 +1197,7 @@ + bool + CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread(void) + { +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + if (!process.IsValid()) + return MIstatus::success; + +@@ -1339,7 +1339,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDOUT(&c, 1) > 0) + { + CMIUtilString str; +@@ -1374,7 +1374,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDERR(&c, 1) > 0) + { + CMIUtilString str; +@@ -1448,22 +1448,22 @@ + bool + CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void) + { +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ if (!sbProcess.IsValid()) + return MIstatus::success; +- lldb::SBTarget &rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget; +- if (!rTarget.IsValid()) ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ if (!sbTarget.IsValid()) + return MIstatus::success; + + bool bOk = MIstatus::success; + + // Check for created threads +- const MIuint nThread = rProcess.GetNumThreads(); ++ const MIuint nThread = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThread; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (!thread.IsValid()) + continue; + +@@ -1500,7 +1500,7 @@ + } + } + +- lldb::SBThread currentThread = rProcess.GetSelectedThread(); ++ lldb::SBThread currentThread = sbProcess.GetSelectedThread(); + if (currentThread.IsValid()) + { + const MIuint threadId = currentThread.GetIndexID(); +@@ -1523,7 +1523,7 @@ + while (it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end()) + { + const MIuint nThreadId = *it; +- lldb::SBThread thread = rProcess.GetThreadAtIndex(nThreadId); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(nThreadId); + if (!thread.IsValid()) + { + // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" +Index: tools/lldb-mi/MICmnLLDBProxySBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBProxySBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBProxySBValue.cpp (working copy) +@@ -129,14 +129,14 @@ + return MIstatus::failure; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + MIuint nBufferSize = 64; + bool bNeedResize = false; + MIchar *pBuffer = static_cast(::malloc(nBufferSize)); + do + { + lldb::SBError error; +- const size_t nReadSize = rProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); ++ const size_t nReadSize = sbProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); + if (nReadSize == (nBufferSize - 1)) + { + bNeedResize = true; +Index: tools/lldb-mi/MICmnLLDBUtilSBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (revision 224992) ++++ tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (working copy) +@@ -219,7 +219,7 @@ + const MIuint nBytes(128); + const MIchar *pBufferMemory = new MIchar[nBytes]; + lldb::SBError error; +- const MIuint64 nReadBytes = rSessionInfo.m_lldbProcess.ReadMemory(addr, (void *)pBufferMemory, nBytes, error); ++ const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, (void *)pBufferMemory, nBytes, error); + MIunused(nReadBytes); + text = CMIUtilString::Format("\\\"%s\\\"", pBufferMemory); + delete[] pBufferMemory; Index: patches/lldbmi_fix_sessioninfo_after_CLI_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_sessioninfo_after_CLI_support.v4.patch @@ -0,0 +1,966 @@ +Index: tools/lldb-mi/MICmdCmdBreak.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdBreak.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdBreak.cpp (working copy) +@@ -232,20 +232,20 @@ + // Ask LLDB to create a breakpoint + bool bOk = MIstatus::success; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + switch (eBrkPtType) + { + case eBreakPoint_ByAddress: +- m_brkPt = rTarget.BreakpointCreateByAddress(nAddress); ++ m_brkPt = sbTarget.BreakpointCreateByAddress(nAddress); + break; + case eBreakPoint_ByFileFn: +- m_brkPt = rTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); ++ m_brkPt = sbTarget.BreakpointCreateByName(strFileFn.c_str(), fileName.c_str()); + break; + case eBreakPoint_ByFileLine: +- m_brkPt = rTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); ++ m_brkPt = sbTarget.BreakpointCreateByLocation(fileName.c_str(), nFileLine); + break; + case eBreakPoint_ByName: +- m_brkPt = rTarget.BreakpointCreateByName(m_brkName.c_str(), rTarget.GetExecutable().GetFilename()); ++ m_brkPt = sbTarget.BreakpointCreateByName(m_brkName.c_str(), sbTarget.GetExecutable().GetFilename()); + break; + case eBreakPoint_count: + case eBreakPoint_NotDefineYet: +@@ -440,7 +440,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const bool bBrkPt = rSessionInfo.m_lldbTarget.BreakpointDelete(static_cast(nBrk)); ++ const bool bBrkPt = rSessionInfo.GetTarget().BreakpointDelete(static_cast(nBrk)); + if (!bBrkPt) + { + const CMIUtilString strBrkNum(CMIUtilString::Format("%d", nBrk)); +@@ -560,7 +560,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtDisabledOk = true; +@@ -700,7 +700,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(nBrk)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(nBrk)); + if (brkPt.IsValid()) + { + m_bBrkPtEnabledOk = true; +@@ -837,7 +837,7 @@ + m_nBrkPtCount = pArgCount->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetIgnoreCount(m_nBrkPtCount); +@@ -972,7 +972,7 @@ + m_strBrkPtExpr += GetRestOfExpressionNotSurroundedInQuotes(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBBreakpoint brkPt = rSessionInfo.m_lldbTarget.FindBreakpointByID(static_cast(m_nBrkPtId)); ++ lldb::SBBreakpoint brkPt = rSessionInfo.GetTarget().FindBreakpointByID(static_cast(m_nBrkPtId)); + if (brkPt.IsValid()) + { + brkPt.SetCondition(m_strBrkPtExpr.c_str()); +Index: tools/lldb-mi/MICmdCmdData.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdData.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdData.cpp (working copy) +@@ -122,8 +122,8 @@ + + const CMIUtilString &rExpression(pArgExpr->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + m_bExpressionValid = (thread.GetNumFrames() > 0); + if (!m_bExpressionValid) + return MIstatus::success; +@@ -410,22 +410,22 @@ + const MIuint nDisasmMode = pArgMode->GetValue(); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); + lldb::addr_t lldbStartAddr = static_cast(nAddrStart); +- lldb::SBInstructionList instructions = rTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, rTarget), nAddrEnd - nAddrStart); ++ lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart); + const MIuint nInstructions = instructions.GetSize(); + for (size_t i = 0; i < nInstructions; i++) + { + const MIchar *pUnknown = "??"; + lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i); +- const MIchar *pStrMnemonic = instrt.GetMnemonic(rTarget); ++ const MIchar *pStrMnemonic = instrt.GetMnemonic(sbTarget); + pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown; + lldb::SBAddress address = instrt.GetAddress(); +- lldb::addr_t addr = address.GetLoadAddress(rTarget); ++ lldb::addr_t addr = address.GetLoadAddress(sbTarget); + const MIchar *pFnName = address.GetFunction().GetName(); + pFnName = (pFnName != nullptr) ? pFnName : pUnknown; + lldb::addr_t addrOffSet = address.GetOffset(); +- const MIchar *pStrOperands = instrt.GetOperands(rTarget); ++ const MIchar *pStrOperands = instrt.GetOperands(sbTarget); + pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown; + + // MI "{address=\"0x%08llx\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}" +@@ -599,9 +599,9 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; +- const MIuint64 nReadBytes = rProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); ++ const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error); + if (nReadBytes != nAddrNumBytes) + { + SetError( +@@ -827,14 +827,14 @@ + CMICmdCmdDataListRegisterNames::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -906,7 +906,6 @@ + , m_constStrArgFormat("fmt") + , m_constStrArgRegNo("regno") + , m_miValueList(true) +- , m_pProcess(nullptr) + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "data-list-register-values"; +@@ -975,13 +974,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ if (!sbProcess.IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } +- m_pProcess = &rProcess; + + const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions()); + CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin(); +@@ -1051,7 +1049,7 @@ + lldb::SBValue + CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const + { +- lldb::SBThread thread = m_pProcess->GetSelectedThread(); ++ lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread(); + lldb::SBFrame frame = thread.GetSelectedFrame(); + lldb::SBValueList registers = frame.GetRegisters(); + const MIuint nRegisters = registers.GetSize(); +@@ -1371,10 +1369,10 @@ + *m_pBufferMemory = static_cast(nValue); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBError error; + lldb::addr_t addr = static_cast(m_nAddr + nAddrOffset); +- const size_t nBytesWritten = rProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); ++ const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error); + if (nBytesWritten != static_cast(m_nCount)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr)); +Index: tools/lldb-mi/MICmdCmdData.h +=================================================================== +--- tools/lldb-mi/MICmdCmdData.h (revision 227847) ++++ tools/lldb-mi/MICmdCmdData.h (working copy) +@@ -263,7 +263,6 @@ + const CMIUtilString m_constStrArgFormat; + const CMIUtilString m_constStrArgRegNo; + CMICmnMIValueList m_miValueList; +- lldb::SBProcess *m_pProcess; + }; + + //++ ============================================================================ +Index: tools/lldb-mi/MICmdCmdExec.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdExec.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdExec.cpp (working copy) +@@ -91,8 +91,8 @@ + lldb::SBError error; + lldb::SBStream errMsg; + uint32_t launch_flags = lldb::LaunchFlags::eLaunchFlagDebug; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.Launch(rSessionInfo.m_rLlldbListener, nullptr, nullptr, nullptr, nullptr, nullptr, +- nullptr, launch_flags, false, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().Launch(rSessionInfo.GetListener(), nullptr, nullptr, nullptr, nullptr, ++ nullptr, nullptr, launch_flags, false, error); + + if ((!process.IsValid()) || (error.Fail())) + { +@@ -100,9 +100,6 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- rSessionInfo.m_lldbProcess = process; +- + if (!CMIDriver::Instance().SetDriverStateRunningDebugging()) + { + const CMIUtilString &rErrMsg(CMIDriver::Instance().GetErrorDescription()); +@@ -137,7 +134,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Give the client '=thread-group-started,id="i1" pid="xyz"' + m_bHasResultRecordExtra = true; + const CMICmnMIValueConst miValueConst2("i1"); +@@ -212,7 +209,7 @@ + { + const MIchar *pCmd = "continue"; + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- const lldb::ReturnStatus rtn = rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); ++ const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(pCmd, m_lldbResult); + MIunused(rtn); + + if (m_lldbResult.GetErrorSize() == 0) +@@ -356,7 +353,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -483,7 +480,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-in"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -610,7 +607,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst-over"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -737,7 +734,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-inst"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -865,7 +862,7 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("thread step-out"); + if (nThreadId != UINT64_MAX) + strCmd += CMIUtilString::Format(" %llu", nThreadId); +@@ -962,7 +959,7 @@ + CMICmdCmdExecInterrupt::Execute(void) + { + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDebugger = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDebugger = rSessionInfo.GetDebugger(); + CMIUtilString strCmd("process interrupt"); + const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult, false); + MIunused(status); +Index: tools/lldb-mi/MICmdCmdFile.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdFile.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdFile.cpp (working copy) +@@ -96,7 +96,7 @@ + CMICmdArgValFile *pArgFile = static_cast(pArgNamedFile); + const CMIUtilString &strExeFilePath(pArgFile->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBError error; + const MIchar *pTargetTriple = nullptr; // Let LLDB discover the triple required + const MIchar *pTargetPlatformName = ""; +@@ -137,8 +137,6 @@ + return MIstatus::failure; + } + +- rSessionInfo.m_lldbTarget = target; +- + return MIstatus::success; + } + +Index: tools/lldb-mi/MICmdCmdGdbInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbInfo.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdGdbInfo.cpp (working copy) +@@ -198,11 +198,11 @@ + bool bOk = rStdout.TextToStdout("~\"From To Syms Read Shared Object Library\""); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBTarget &rTarget = rSessionInfo.m_lldbTarget; +- const MIuint nModules = rTarget.GetNumModules(); ++ lldb::SBTarget sbTarget = rSessionInfo.GetTarget(); ++ const MIuint nModules = sbTarget.GetNumModules(); + for (MIuint i = 0; bOk && (i < nModules); i++) + { +- lldb::SBModule module = rTarget.GetModuleAtIndex(i); ++ lldb::SBModule module = sbTarget.GetModuleAtIndex(i); + if (module.IsValid()) + { + const CMIUtilString strModuleFilePath(module.GetFileSpec().GetDirectory()); +@@ -216,7 +216,7 @@ + for (MIuint j = 0; j < nSections; j++) + { + lldb::SBSection section = module.GetSectionAtIndex(j); +- lldb::addr_t addrLoad = section.GetLoadAddress(rTarget); ++ lldb::addr_t addrLoad = section.GetLoadAddress(sbTarget); + if (addrLoad != (lldb::addr_t) - 1) + { + if (!bHaveAddrLoad) +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.GetProcess().Detach(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +@@ -234,17 +234,17 @@ + m_bIsI1 = true; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + +- // Note do not check for rProcess is IsValid(), continue ++ // Note do not check for sbProcess is IsValid(), continue + + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + + if (thread.IsValid()) + { +@@ -292,9 +292,9 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); +@@ -328,20 +328,20 @@ + miTuple.Add(miValueResult2); + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- if (rSessionInfo.m_lldbProcess.IsValid()) ++ if (rSessionInfo.GetProcess().IsValid()) + { +- const lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ const lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + const CMIUtilString strPid(CMIUtilString::Format("%lld", pid)); + const CMICmnMIValueConst miValueConst3(strPid); + const CMICmnMIValueResult miValueResult3("pid", miValueConst3); + miTuple.Add(miValueResult3); + } + +- if (rSessionInfo.m_lldbTarget.IsValid()) ++ if (rSessionInfo.GetTarget().IsValid()) + { +- lldb::SBTarget &rTrgt = rSessionInfo.m_lldbTarget; +- const MIchar *pDir = rTrgt.GetExecutable().GetDirectory(); +- const MIchar *pFileName = rTrgt.GetExecutable().GetFilename(); ++ lldb::SBTarget sbTrgt = rSessionInfo.GetTarget(); ++ const MIchar *pDir = sbTrgt.GetExecutable().GetDirectory(); ++ const MIchar *pFileName = sbTrgt.GetExecutable().GetFilename(); + const CMIUtilString strFile(CMIUtilString::Format("%s/%s", pDir, pFileName)); + const CMICmnMIValueConst miValueConst4(strFile); + const CMICmnMIValueResult miValueResult4("executable", miValueConst4); +@@ -470,7 +470,7 @@ + const CMIUtilString &rStrCommand(pArgCommand->GetValue()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + const lldb::ReturnStatus rtn = +- rSessionInfo.m_rLldbDebugger.GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); ++ rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(rStrCommand.c_str(), m_lldbResult, true); + MIunused(rtn); + + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -111,8 +111,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadFrames = thread.GetNumFrames(); + + return MIstatus::success; +@@ -237,8 +237,8 @@ + const MIuint nFrameLow = pArgFrameLow->GetFound() ? pArgFrameLow->GetValue() : 0; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + MIuint nThreadFrames = thread.GetNumFrames(); + + // Adjust nThreadFrames for the nFrameHigh argument as we use nFrameHigh+1 in the min calc as the arg +@@ -414,8 +414,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +@@ -583,8 +583,8 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdTarget.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdTarget.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdTarget.cpp (working copy) +@@ -100,7 +100,7 @@ + + // Check we have a valid target + // Note: target created via 'file-exec-and-symbols' command +- if (!rSessionInfo.m_lldbTarget.IsValid()) ++ if (!rSessionInfo.GetTarget().IsValid()) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; +@@ -120,7 +120,7 @@ + // Ask LLDB to collect to the target port + const MIchar *pPlugin("gdb-remote"); + lldb::SBError error; +- lldb::SBProcess process = rSessionInfo.m_lldbTarget.ConnectRemote(rSessionInfo.m_rLlldbListener, strUrl.c_str(), pPlugin, error); ++ lldb::SBProcess process = rSessionInfo.GetTarget().ConnectRemote(rSessionInfo.GetListener(), strUrl.c_str(), pPlugin, error); + + // Verify that we have managed to connect successfully + lldb::SBStream errMsg; +@@ -135,16 +135,11 @@ + return MIstatus::failure; + } + +- // Save the process in the session info +- // Note: Order is important here since this process handle may be used by CMICmnLLDBDebugHandleEvents +- // which can fire when interpreting via HandleCommand() below. +- rSessionInfo.m_lldbProcess = process; +- + // Set the environment path if we were given one + CMIUtilString strWkDir; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataKeyWkDir, strWkDir)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + if (!rDbgr.SetCurrentPlatformSDKRoot(strWkDir.c_str())) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FNFAILED), m_cmdData.strMiCmd.c_str(), "target-select")); +@@ -156,7 +151,7 @@ + CMIUtilString strSolibPath; + if (rSessionInfo.SharedDataRetrieve(rSessionInfo.m_constStrSharedDataSolibPath, strSolibPath)) + { +- lldb::SBDebugger &rDbgr = rSessionInfo.m_rLldbDebugger; ++ lldb::SBDebugger &rDbgr = rSessionInfo.GetDebugger(); + lldb::SBCommandInterpreter cmdIterpreter = rDbgr.GetCommandInterpreter(); + + CMIUtilString strCmdString = CMIUtilString::Format("target modules search-paths add . %s", strSolibPath.c_str()); +@@ -190,7 +185,7 @@ + m_miResultRecord = miRecordResult; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::pid_t pid = rSessionInfo.m_lldbProcess.GetProcessID(); ++ lldb::pid_t pid = rSessionInfo.GetProcess().GetProcessID(); + // Prod the client i.e. Eclipse with out-of-band results to help it 'continue' because it is using LLDB debugger + // Give the client '=thread-group-started,id="i1"' + m_bHasResultRecordExtra = true; +Index: tools/lldb-mi/MICmdCmdThread.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdThread.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdThread.cpp (working copy) +@@ -99,12 +99,12 @@ + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + + if (m_bSingleThread) + { +- thread = rProcess.GetThreadByIndexID(nThreadId); ++ thread = sbProcess.GetThreadByIndexID(nThreadId); + m_bThreadInvalid = thread.IsValid(); + if (!m_bThreadInvalid) + return MIstatus::success; +@@ -120,10 +120,10 @@ + + // Multiple threads + m_vecMIValueTuple.clear(); +- const MIuint nThreads = rProcess.GetNumThreads(); ++ const MIuint nThreads = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThreads; i++) + { +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (thread.IsValid()) + { + CMICmnMIValueTuple miTuple; +Index: tools/lldb-mi/MICmdCmdVar.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdVar.cpp (revision 227847) ++++ tools/lldb-mi/MICmdCmdVar.cpp (working copy) +@@ -169,8 +169,8 @@ + m_strVarName = CMIUtilString::Format("var%u", CMICmnLLDBDebugSessionInfoVarObj::VarObjIdGet()); + CMICmnLLDBDebugSessionInfoVarObj::VarObjIdInc(); + } +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = (nThreadId != UINT64_MAX) ? rProcess.GetThreadByIndexID(nThreadId) : rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_nThreadId = thread.GetIndexID(); + lldb::SBFrame frame = thread.GetFrameAtIndex(nFrame); + lldb::SBValue value = frame.FindVariable(rStrExpression.c_str()); +@@ -519,8 +519,8 @@ + vrwbChanged = false; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + if (thread.GetNumFrames() == 0) + { + return MIstatus::success; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 227847) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -47,9 +47,7 @@ + // Throws: None. + //-- + CMICmnLLDBDebugSessionInfo::CMICmnLLDBDebugSessionInfo(void) +- : m_rLldbDebugger(CMICmnLLDBDebugger::Instance().GetTheDebugger()) +- , m_rLlldbListener(CMICmnLLDBDebugger::Instance().GetTheListener()) +- , m_nBrkPointCntMax(INT32_MAX) ++ : m_nBrkPointCntMax(INT32_MAX) + , m_currentSelectedThread(LLDB_INVALID_THREAD_ID) + , m_constStrSharedDataKeyWkDir("Working Directory") + , m_constStrSharedDataSolibPath("Solib Path") +@@ -226,7 +224,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -299,7 +297,7 @@ + bool + CMICmnLLDBDebugSessionInfo::GetThreadFrames2(const SMICmdData &vCmdData, const MIuint vThreadIdx, CMIUtilString &vwrThreadFrames) + { +- lldb::SBThread thread = m_lldbProcess.GetThreadByIndexID(vThreadIdx); ++ lldb::SBThread thread = GetProcess().GetThreadByIndexID(vThreadIdx); + const uint32_t nFrames = thread.GetNumFrames(); + if (nFrames == 0) + { +@@ -1329,7 +1327,7 @@ + const MIchar *pFn = pUnkwn; + const MIchar *pFilePath = pUnkwn; + size_t nLine = 0; +- const size_t nAddr = brkPtAddr.GetLoadAddress(m_lldbTarget); ++ const size_t nAddr = brkPtAddr.GetLoadAddress(GetTarget()); + + lldb::SBCompileUnit rCmplUnit = symbolCntxt.GetCompileUnit(); + if (rCmplUnit.IsValid()) +@@ -1356,3 +1354,55 @@ + + return MIstatus::success; + } ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current debugger. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBDebugger - current debugger. ++// Throws: None. ++//-- ++lldb::SBDebugger & ++CMICmnLLDBDebugSessionInfo::GetDebugger() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheDebugger(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current listener. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBListener - current listener. ++// Throws: None. ++//-- ++lldb::SBListener & ++CMICmnLLDBDebugSessionInfo::GetListener() const ++{ ++ return CMICmnLLDBDebugger::Instance().GetTheListener(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current target. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBTarget - current target. ++// Throws: None. ++//-- ++lldb::SBTarget ++CMICmnLLDBDebugSessionInfo::GetTarget() const ++{ ++ return GetDebugger().GetSelectedTarget(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Get current process. ++// Type: Method. ++// Args: None. ++// Return: lldb::SBProcess - current process. ++// Throws: None. ++//-- ++lldb::SBProcess ++CMICmnLLDBDebugSessionInfo::GetProcess() const ++{ ++ return GetTarget().GetProcess(); ++} +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 227847) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -156,14 +156,14 @@ + bool RecordBrkPtInfo(const MIuint vnBrkPtId, const SBrkPtInfo &vrBrkPtInfo); + bool RecordBrkPtInfoGet(const MIuint vnBrkPtId, SBrkPtInfo &vrwBrkPtInfo) const; + bool RecordBrkPtInfoDelete(const MIuint vnBrkPtId); ++ lldb::SBDebugger &GetDebugger() const; ++ lldb::SBListener &GetListener() const; ++ lldb::SBTarget GetTarget() const; ++ lldb::SBProcess GetProcess() const; + + // Attributes: + public: + // The following are available to all command instances +- lldb::SBDebugger &m_rLldbDebugger; +- lldb::SBListener &m_rLlldbListener; +- lldb::SBTarget m_lldbTarget; +- lldb::SBProcess m_lldbProcess; + const MIuint m_nBrkPointCntMax; + VecActiveThreadId_t m_vecActiveThreadId; + lldb::tid_t m_currentSelectedThread; +Index: tools/lldb-mi/MICmnLLDBDebugger.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugger.cpp (revision 227847) ++++ tools/lldb-mi/MICmnLLDBDebugger.cpp (working copy) +@@ -148,7 +148,8 @@ + + // Explicitly delete the remote target in case MI needs to exit prematurely otherwise + // LLDB debugger may hang in its Destroy() fn waiting on events +- m_lldbDebugger.DeleteTarget(CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget); ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ m_lldbDebugger.DeleteTarget(sbTarget); + + // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014 + // It appears we need to wait as hang does not occur when hitting a debug breakpoint here +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 227847) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -722,9 +722,9 @@ + return MIstatus::success; + + bool bOk = MIstatus::success; +- lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBTarget target = rProcess.GetTarget(); ++ lldb::SBDebugger &rDebugger = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBTarget target = sbProcess.GetTarget(); + if (rDebugger.GetSelectedTarget() == target) + { + if (!UpdateSelectedThread()) +@@ -768,8 +768,8 @@ + + const MIchar *pEventType = ""; + bool bOk = MIstatus::success; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const lldb::StopReason eStoppedReason = sbProcess.GetSelectedThread().GetStopReason(); + switch (eStoppedReason) + { + case lldb::eStopReasonInvalid: +@@ -831,8 +831,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 nStopReason = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); + switch (nStopReason) + { + case 2: // Terminal interrupt signal. SIGINT +@@ -868,7 +868,7 @@ + const CMICmnMIValueConst miValueConst3("Segmentation fault"); + const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); + bOk = bOk && miOutOfBandRecord.Add(miValueResult3); +- const CMIUtilString strThreadId(CMIUtilString::Format("%d", rProcess.GetSelectedThread().GetIndexID())); ++ const CMIUtilString strThreadId(CMIUtilString::Format("%d", sbProcess.GetSelectedThread().GetIndexID())); + const CMICmnMIValueConst miValueConst4(strThreadId); + const CMICmnMIValueResult miValueResult4("thread-id", miValueConst4); + bOk = bOk && miOutOfBandRecord.Add(miValueResult4); +@@ -881,12 +881,12 @@ + } + break; + case 19: +- if (rProcess.IsValid()) +- rProcess.Continue(); ++ if (sbProcess.IsValid()) ++ sbProcess.Continue(); + break; + case 5: // Trace/breakpoint trap. SIGTRAP + { +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrames = thread.GetNumFrames(); + if (nFrames > 0) + { +@@ -899,9 +899,9 @@ + + if (CMIUtilString::Compare(threadCloneFn, fnName)) + { +- if (rProcess.IsValid()) ++ if (sbProcess.IsValid()) + { +- rProcess.Continue(); ++ sbProcess.Continue(); + vwrbShouldBrk = true; + break; + } +@@ -942,8 +942,8 @@ + CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple) + { + CMIUtilString strThreadFrame; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -997,9 +997,9 @@ + return MIstatus::failure; + } + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); +- lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex((MIuint)brkPtId); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ const MIuint64 brkPtId = sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); ++ lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().GetTarget().GetBreakpointAtIndex((MIuint)brkPtId); + + return MiStoppedAtBreakPoint(brkPtId, brkPt); + } +@@ -1018,8 +1018,8 @@ + { + bool bOk = MIstatus::success; + +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1121,8 +1121,8 @@ + CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace(void) + { + bool bOk = true; +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- lldb::SBThread thread = rProcess.GetSelectedThread(); ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ lldb::SBThread thread = sbProcess.GetSelectedThread(); + const MIuint nFrame = thread.GetNumFrames(); + if (nFrame == 0) + { +@@ -1200,7 +1200,7 @@ + bool + CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread(void) + { +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + if (!process.IsValid()) + return MIstatus::success; + +@@ -1342,7 +1342,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDOUT(&c, 1) > 0) + { + CMIUtilString str; +@@ -1377,7 +1377,7 @@ + char c; + size_t nBytes = 0; + CMIUtilString text; +- lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); ++ lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().GetDebugger().GetSelectedTarget().GetProcess(); + while (process.GetSTDERR(&c, 1) > 0) + { + CMIUtilString str; +@@ -1451,22 +1451,22 @@ + bool + CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges(void) + { +- lldb::SBProcess &rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; +- if (!rProcess.IsValid()) ++ lldb::SBProcess sbProcess = CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); ++ if (!sbProcess.IsValid()) + return MIstatus::success; +- lldb::SBTarget &rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget; +- if (!rTarget.IsValid()) ++ lldb::SBTarget sbTarget = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); ++ if (!sbTarget.IsValid()) + return MIstatus::success; + + bool bOk = MIstatus::success; + + // Check for created threads +- const MIuint nThread = rProcess.GetNumThreads(); ++ const MIuint nThread = sbProcess.GetNumThreads(); + for (MIuint i = 0; i < nThread; i++) + { + // GetThreadAtIndex() uses a base 0 index + // GetThreadByIndexID() uses a base 1 index +- lldb::SBThread thread = rProcess.GetThreadAtIndex(i); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); + if (!thread.IsValid()) + continue; + +@@ -1503,7 +1503,7 @@ + } + } + +- lldb::SBThread currentThread = rProcess.GetSelectedThread(); ++ lldb::SBThread currentThread = sbProcess.GetSelectedThread(); + if (currentThread.IsValid()) + { + const MIuint threadId = currentThread.GetIndexID(); +@@ -1526,7 +1526,7 @@ + while (it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end()) + { + const MIuint nThreadId = *it; +- lldb::SBThread thread = rProcess.GetThreadAtIndex(nThreadId); ++ lldb::SBThread thread = sbProcess.GetThreadAtIndex(nThreadId); + if (!thread.IsValid()) + { + // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" +Index: tools/lldb-mi/MICmnLLDBProxySBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBProxySBValue.cpp (revision 227847) ++++ tools/lldb-mi/MICmnLLDBProxySBValue.cpp (working copy) +@@ -129,14 +129,14 @@ + return MIstatus::failure; + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); +- lldb::SBProcess &rProcess = rSessionInfo.m_lldbProcess; ++ lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + MIuint nBufferSize = 64; + bool bNeedResize = false; + MIchar *pBuffer = static_cast(::malloc(nBufferSize)); + do + { + lldb::SBError error; +- const size_t nReadSize = rProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); ++ const size_t nReadSize = sbProcess.ReadCStringFromMemory((lldb::addr_t)nNum, pBuffer, nBufferSize, error); + if (nReadSize == (nBufferSize - 1)) + { + bNeedResize = true; +Index: tools/lldb-mi/MICmnLLDBUtilSBValue.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (revision 227847) ++++ tools/lldb-mi/MICmnLLDBUtilSBValue.cpp (working copy) +@@ -219,7 +219,7 @@ + const MIuint nBytes(128); + const MIchar *pBufferMemory = new MIchar[nBytes]; + lldb::SBError error; +- const MIuint64 nReadBytes = rSessionInfo.m_lldbProcess.ReadMemory(addr, (void *)pBufferMemory, nBytes, error); ++ const MIuint64 nReadBytes = rSessionInfo.GetProcess().ReadMemory(addr, (void *)pBufferMemory, nBytes, error); + MIunused(nReadBytes); + text = CMIUtilString::Format("\\\"%s\\\"", pBufferMemory); + delete[] pBufferMemory; Index: patches/lldbmi_fix_stack_list_commands.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_stack_list_commands.patch @@ -0,0 +1,660 @@ +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 228386) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -10,7 +10,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_stackargs(self): + """Test that 'lldb-mi --interpreter' can shows arguments.""" + +@@ -35,7 +34,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_locals(self): + """Test that 'lldb-mi --interpreter' can shows local variables.""" + +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 228386) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -413,6 +413,14 @@ + } + } + ++ const MIuint nPrintValues = pArgPrintValues->GetValue(); ++ if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ const CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = static_cast(nPrintValues); ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); +@@ -433,7 +441,7 @@ + lldb::SBFrame frame = thread.GetFrameAtIndex(i); + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, miValueList)) ++ if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, eVarInfoFormat, miValueList)) + return MIstatus::failure; + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%d", i)); + const CMICmnMIValueResult miValueResult("level", miValueConst); +@@ -561,6 +569,7 @@ + { + CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread); + CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame); ++ CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues); + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +@@ -572,6 +581,7 @@ + return MIstatus::failure; + } + } ++ + MIuint64 nFrame = UINT64_MAX; + if (pArgFrame->GetFound()) + { +@@ -582,6 +592,14 @@ + } + } + ++ const MIuint nPrintValues = pArgPrintValues->GetValue(); ++ if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ const CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat = static_cast(nPrintValues); ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); +@@ -596,12 +614,11 @@ + return MIstatus::success; + } + +- const MIuint nFrames = thread.GetNumFrames(); +- MIunused(nFrames); + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); ++ + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals; +- if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) ++ if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, eVarInfoFormat, miValueList)) + return MIstatus::failure; + + m_miValueList = miValueList; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -253,7 +253,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = eVariableType_Arguments; +- if (!MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) ++ if (!MIResponseFormVariableInfo(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + + const MIchar *pUnknown = "??"; +@@ -326,7 +326,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = eVariableType_Arguments; +- if (!MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) ++ if (!MIResponseFormVariableInfo2(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + + const MIchar *pUnknown = "??"; +@@ -646,6 +646,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -653,7 +654,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -686,6 +687,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -693,7 +695,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -709,7 +711,7 @@ + for (MIuint i = 0; bOk && (i < nArgs); i++) + { + lldb::SBValue value = listArg.GetValueAtIndex(i); +- bOk = GetVariableInfo(nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth); ++ bOk = GetVariableInfo(nMaxRecusiveDepth, value, false, veVarInfoFormat, vwrMiValueList, nCurrentRecursiveDepth); + } + + return bOk; +@@ -723,6 +725,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -730,7 +733,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -746,7 +749,7 @@ + for (MIuint i = 0; bOk && (i < nArgs); i++) + { + lldb::SBValue value = listArg.GetValueAtIndex(i); +- bOk = GetVariableInfo2(nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth); ++ bOk = GetVariableInfo2(nMaxRecusiveDepth, value, false, veVarInfoFormat, vwrMiValueList, nCurrentRecursiveDepth); + } + + return bOk; +@@ -761,15 +764,17 @@ + // vrValue - (R) LLDB value object. + // vbIsChildValue - (R) True = Value object is a child of a higher Value object, + // - False = Value object not a child. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // vnDepth - (RW) The current recursive depth of this function. +-// // Return: MIstatus::success - Functional succeeded. ++// Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmnLLDBDebugSessionInfo::GetVariableInfo(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, ++ MIuint &vrwnDepth) + { + // *** Update GetVariableInfo2() with any code changes here *** + +@@ -807,46 +812,78 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else if (bIsPointerType && utilValue.IsChildCharType()) + { +- // Append string text to the parent value information +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- +- const CMIUtilString &rText(utilValue.GetChildValueCString()); +- if (rText.empty()) ++ switch (veVarInfoFormat) + { +- const CMICmnMIValueConst miValueConst(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); +- } +- else +- { +- if (utilValue.IsValueUnknown()) ++ case eVariableInfoFormat_NoValues: + { +- const CMICmnMIValueConst miValueConst(rText); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); + } +- else ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: + { +- // Note code that has const in will not show the text suffix to the string pointer +- // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this +- // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); +- const CMICmnMIValueResult miValueResult("value", miValueConst); ++ // Append string text to the parent value information ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); ++ ++ const CMIUtilString &rText(utilValue.GetChildValueCString()); ++ if (rText.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ if (utilValue.IsValueUnknown()) ++ { ++ const CMICmnMIValueConst miValueConst(rText); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ // Note code that has const in will not show the text suffix to the string pointer ++ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this ++ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ } ++ break; + } ++ default: ++ break; + } + return vwrMiValueList.Add(miValueTuple); + } +@@ -863,30 +900,62 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else + { +- // Build parent child composite types +- CMICmnMIValueList miValueList(true); +- for (MIuint i = 0; bOk && (i < nChildren); i++) ++ switch (veVarInfoFormat) + { +- lldb::SBValue member = rValue.GetChildAtIndex(i); +- bOk = GetVariableInfo(vnMaxDepth, member, true, miValueList, ++vrwnDepth); ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ // Build parent child composite types ++ CMICmnMIValueList miValueList(true); ++ for (MIuint i = 0; bOk && (i < nChildren); i++) ++ { ++ lldb::SBValue member = rValue.GetChildAtIndex(i); ++ bOk = GetVariableInfo(vnMaxDepth, member, true, veVarInfoFormat, miValueList, ++vrwnDepth); ++ } ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; + } +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); + } + } +@@ -900,6 +969,7 @@ + // vrValue - (R) LLDB value object. + // vbIsChildValue - (R) True = Value object is a child of a higher Value object, + // - False = Value object not a child. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // vnDepth - (RW) The current recursive depth of this function. + // // Return: MIstatus::success - Functional succeeded. +@@ -908,7 +978,8 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, ++ MIuint &vrwnDepth) + { + // *** Update GetVariableInfo() with any code changes here *** + +@@ -935,64 +1006,112 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else if (utilValue.IsChildCharType()) + { +- // Append string text to the parent value information +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- +- const CMIUtilString &rText(utilValue.GetChildValueCString()); +- if (rText.empty()) ++ switch (veVarInfoFormat) + { +- const CMICmnMIValueConst miValueConst(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); +- } +- else +- { +- if (utilValue.IsValueUnknown()) ++ case eVariableInfoFormat_NoValues: + { +- const CMICmnMIValueConst miValueConst(rText); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); + } +- else ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: + { +- // Note code that has const in will not show the text suffix to the string pointer +- // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this +- // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); +- const CMICmnMIValueResult miValueResult("value", miValueConst); ++ // Append string text to the parent value information ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); ++ ++ const CMIUtilString &rText(utilValue.GetChildValueCString()); ++ if (rText.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ if (utilValue.IsValueUnknown()) ++ { ++ const CMICmnMIValueConst miValueConst(rText); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ // Note code that has const in will not show the text suffix to the string pointer ++ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this ++ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ } ++ break; + } ++ default: ++ break; + } + return vwrMiValueList.Add(miValueTuple); + } + else + { +- // Build parent child composite types +- CMICmnMIValueList miValueList(true); +- for (MIuint i = 0; bOk && (i < nChildren); i++) ++ switch (veVarInfoFormat) + { +- lldb::SBValue member = rValue.GetChildAtIndex(i); +- bOk = GetVariableInfo(vnMaxDepth, member, true, miValueList, ++vrwnDepth); ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ // Build parent child composite types ++ CMICmnMIValueList miValueList(true); ++ for (MIuint i = 0; bOk && (i < nChildren); i++) ++ { ++ lldb::SBValue member = rValue.GetChildAtIndex(i); ++ bOk = GetVariableInfo(vnMaxDepth, member, true, veVarInfoFormat, miValueList, ++vrwnDepth); ++ } ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; + } +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); + } + } +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -117,6 +117,17 @@ + eVariableType_Arguments = (1u << 3) // Arguments. + }; + ++ //++ =================================================================== ++ // Details: Determine the information that should be shown by using MIResponseFormVariableInfo family functions. ++ //-- ++ enum VariableInfoFormat_e ++ { ++ eVariableInfoFormat_NoValues, ++ eVariableInfoFormat_AllValues, ++ eVariableInfoFormat_SimpleValues, ++ kNumVariableInfoFormats ++ }; ++ + // Typedefs: + public: + typedef std::vector VecActiveThreadId_t; +@@ -148,9 +159,12 @@ + bool MIResponseFormThreadInfo(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); + bool MIResponseFormThreadInfo2(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); + bool MIResponseFormThreadInfo3(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); +- bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); +- bool MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); +- bool MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); + bool MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); + bool MIResponseFormBrkPtInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); + bool GetBrkPtInfo(const lldb::SBBreakpoint &vBrkPt, SBrkPtInfo &vrwBrkPtInfo) const; +@@ -188,9 +202,9 @@ + void operator=(const CMICmnLLDBDebugSessionInfo &); + // + bool GetVariableInfo(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); + bool GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); + + // Overridden: + private: +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -1081,7 +1081,7 @@ + { + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList); ++ bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList); + + CMICmnMIValueTuple miValueTuple; + bOk = bOk && rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple); +@@ -1157,7 +1157,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) ++ if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + CMICmnMIValueTuple miValueTuple; + if (!rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple)) +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 228386) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -254,6 +254,7 @@ + {IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK, "Command '%s'. LLDB unable to read entire memory block of %u bytes at address 0x%08x"}, + {IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to read memory block of %u bytes at address 0x%08x: %s "}, + {IDS_CMD_ERR_INVALID_PROCESS, "Command '%s'. Invalid process during debug session"}, ++ {IDS_CMD_ERR_INVALID_PRINT_VALUES, "Command '%s'. Unknown value for PRINT_VALUES: must be: 0 for no-values, 1 for all-values, 2 for simple-values"}, + {IDS_CMD_ERR_INVALID_FORMAT_TYPE, "Command '%s'. Invalid var format type '%s'"}, + {IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND, "Command '%s'. Breakpoint information for breakpoint ID %d not found"}, + {IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to write memory block of %u bytes at address 0x%08x: %s "}, +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 228386) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -270,6 +270,7 @@ + IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK, + IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, + IDS_CMD_ERR_INVALID_PROCESS, ++ IDS_CMD_ERR_INVALID_PRINT_VALUES, + IDS_CMD_ERR_INVALID_FORMAT_TYPE, + IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND, + IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES, Index: patches/lldbmi_fix_stack_list_commands.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_fix_stack_list_commands.v2.patch @@ -0,0 +1,822 @@ +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 228386) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -10,7 +10,6 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_stackargs(self): + """Test that 'lldb-mi --interpreter' can shows arguments.""" + +@@ -27,15 +26,26 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- # Test arguments +- self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work ++ # Test -stack-list-arguments: use 0 or --no-values ++ self.runCmd("-stack-list-arguments 0") + self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") ++ self.runCmd("-stack-list-arguments --no-values") ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") ++ ++ # Test -stack-list-arguments: use 1 or --all-values + self.runCmd("-stack-list-arguments 1") + self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ self.runCmd("-stack-list-arguments --all-values") ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") + ++ # Test -stack-list-arguments: use 2 or --simple-values ++ self.runCmd("-stack-list-arguments 2") ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ self.runCmd("-stack-list-arguments --simple-values") ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_locals(self): + """Test that 'lldb-mi --interpreter' can shows local variables.""" + +@@ -53,12 +63,24 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- # Test locals +- self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work ++ # Test -stack-list-locals: use 0 or --no-values ++ self.runCmd("-stack-list-locals 0") + self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") ++ self.runCmd("-stack-list-locals --no-values") ++ self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") ++ ++ # Test -stack-list-locals: use 1 or --all-values + self.runCmd("-stack-list-locals 1") + self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ self.runCmd("-stack-list-locals --all-values") ++ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + ++ # Test -stack-list-locals: use 2 or --simple-values ++ self.runCmd("-stack-list-locals 2") ++ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ self.runCmd("-stack-list-locals --simple-values") ++ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_stackdepth(self): +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 228386) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -350,6 +350,9 @@ + , m_miValueList(true) + , m_constStrArgThread("thread") + , m_constStrArgPrintValues("print-values") ++ , m_constStrArgNoValues("no-values") ++ , m_constStrArgAllValues("all-values") ++ , m_constStrArgSimpleValues("simple-values") + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "stack-list-arguments"; +@@ -383,7 +386,10 @@ + { + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); +- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, true, false))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true))); + return (bOk && ParseValidateCmdOptions()); + } + +@@ -401,6 +407,9 @@ + { + CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread); + CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues); ++ CMICMDBASE_GETOPTION(pArgNoValues, OptionLong, m_constStrArgNoValues); ++ CMICMDBASE_GETOPTION(pArgAllValues, OptionLong, m_constStrArgAllValues); ++ CMICMDBASE_GETOPTION(pArgSimpleValues, OptionLong, m_constStrArgSimpleValues); + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +@@ -413,6 +422,29 @@ + } + } + ++ CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat; ++ if (pArgPrintValues->GetFound()) ++ { ++ const MIuint nPrintValues = pArgPrintValues->GetValue(); ++ if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ eVarInfoFormat = static_cast(nPrintValues); ++ } ++ else if (pArgNoValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues; ++ else if (pArgAllValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues; ++ else if (pArgSimpleValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues; ++ else ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); +@@ -433,7 +465,7 @@ + lldb::SBFrame frame = thread.GetFrameAtIndex(i); + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, miValueList)) ++ if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, eVarInfoFormat, miValueList)) + return MIstatus::failure; + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%d", i)); + const CMICmnMIValueResult miValueResult("level", miValueConst); +@@ -508,6 +540,9 @@ + , m_constStrArgThread("thread") + , m_constStrArgFrame("frame") + , m_constStrArgPrintValues("print-values") ++ , m_constStrArgNoValues("no-values") ++ , m_constStrArgAllValues("all-values") ++ , m_constStrArgSimpleValues("simple-values") + { + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "stack-list-locals"; +@@ -543,7 +578,10 @@ + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); +- bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, true, false))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true))); ++ bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true))); + return (bOk && ParseValidateCmdOptions()); + } + +@@ -561,6 +599,10 @@ + { + CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread); + CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame); ++ CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues); ++ CMICMDBASE_GETOPTION(pArgNoValues, OptionLong, m_constStrArgNoValues); ++ CMICMDBASE_GETOPTION(pArgAllValues, OptionLong, m_constStrArgAllValues); ++ CMICMDBASE_GETOPTION(pArgSimpleValues, OptionLong, m_constStrArgSimpleValues); + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; +@@ -572,6 +614,7 @@ + return MIstatus::failure; + } + } ++ + MIuint64 nFrame = UINT64_MAX; + if (pArgFrame->GetFound()) + { +@@ -582,6 +625,29 @@ + } + } + ++ CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat; ++ if (pArgPrintValues->GetFound()) ++ { ++ const MIuint nPrintValues = pArgPrintValues->GetValue(); ++ if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ eVarInfoFormat = static_cast(nPrintValues); ++ } ++ else if (pArgNoValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues; ++ else if (pArgAllValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues; ++ else if (pArgSimpleValues->GetFound()) ++ eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues; ++ else ++ { ++ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); ++ return MIstatus::failure; ++ } ++ + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); +@@ -596,12 +662,11 @@ + return MIstatus::success; + } + +- const MIuint nFrames = thread.GetNumFrames(); +- MIunused(nFrames); + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); ++ + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals; +- if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) ++ if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, eVarInfoFormat, miValueList)) + return MIstatus::failure; + + m_miValueList = miValueList; +Index: tools/lldb-mi/MICmdCmdStack.h +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.h (revision 228386) ++++ tools/lldb-mi/MICmdCmdStack.h (working copy) +@@ -143,7 +143,10 @@ + bool m_bThreadInvalid; // True = yes invalid thread, false = thread object valid + CMICmnMIValueList m_miValueList; + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option +- const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command ++ const CMIUtilString m_constStrArgPrintValues; ++ const CMIUtilString m_constStrArgNoValues; ++ const CMIUtilString m_constStrArgAllValues; ++ const CMIUtilString m_constStrArgSimpleValues; + }; + + //++ ============================================================================ +@@ -179,5 +182,8 @@ + CMICmnMIValueList m_miValueList; + const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option + const CMIUtilString m_constStrArgFrame; // Not specified in MI spec but Eclipse gives this option +- const CMIUtilString m_constStrArgPrintValues; // Not handled by *this command ++ const CMIUtilString m_constStrArgPrintValues; ++ const CMIUtilString m_constStrArgNoValues; ++ const CMIUtilString m_constStrArgAllValues; ++ const CMIUtilString m_constStrArgSimpleValues; + }; +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -253,7 +253,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = eVariableType_Arguments; +- if (!MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) ++ if (!MIResponseFormVariableInfo(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + + const MIchar *pUnknown = "??"; +@@ -326,7 +326,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = eVariableType_Arguments; +- if (!MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) ++ if (!MIResponseFormVariableInfo2(frame, maskVarTypes, eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + + const MIchar *pUnknown = "??"; +@@ -646,6 +646,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -653,7 +654,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -686,6 +687,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -693,7 +695,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -709,7 +711,7 @@ + for (MIuint i = 0; bOk && (i < nArgs); i++) + { + lldb::SBValue value = listArg.GetValueAtIndex(i); +- bOk = GetVariableInfo(nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth); ++ bOk = GetVariableInfo(nMaxRecusiveDepth, value, false, veVarInfoFormat, vwrMiValueList, nCurrentRecursiveDepth); + } + + return bOk; +@@ -723,6 +725,7 @@ + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. + // vMaskVarTypes - (R) Construed according to VariableType_e. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -730,7 +733,7 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, +- CMICmnMIValueList &vwrMiValueList) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList) + { + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); +@@ -746,7 +749,7 @@ + for (MIuint i = 0; bOk && (i < nArgs); i++) + { + lldb::SBValue value = listArg.GetValueAtIndex(i); +- bOk = GetVariableInfo2(nMaxRecusiveDepth, value, false, vwrMiValueList, nCurrentRecursiveDepth); ++ bOk = GetVariableInfo2(nMaxRecusiveDepth, value, false, veVarInfoFormat, vwrMiValueList, nCurrentRecursiveDepth); + } + + return bOk; +@@ -761,15 +764,17 @@ + // vrValue - (R) LLDB value object. + // vbIsChildValue - (R) True = Value object is a child of a higher Value object, + // - False = Value object not a child. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // vnDepth - (RW) The current recursive depth of this function. +-// // Return: MIstatus::success - Functional succeeded. ++// Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. + // Throws: None. + //-- + bool + CMICmnLLDBDebugSessionInfo::GetVariableInfo(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, ++ MIuint &vrwnDepth) + { + // *** Update GetVariableInfo2() with any code changes here *** + +@@ -807,46 +812,78 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else if (bIsPointerType && utilValue.IsChildCharType()) + { +- // Append string text to the parent value information +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- +- const CMIUtilString &rText(utilValue.GetChildValueCString()); +- if (rText.empty()) ++ switch (veVarInfoFormat) + { +- const CMICmnMIValueConst miValueConst(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); +- } +- else +- { +- if (utilValue.IsValueUnknown()) ++ case eVariableInfoFormat_NoValues: + { +- const CMICmnMIValueConst miValueConst(rText); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); + } +- else ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: + { +- // Note code that has const in will not show the text suffix to the string pointer +- // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this +- // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); +- const CMICmnMIValueResult miValueResult("value", miValueConst); ++ // Append string text to the parent value information ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); ++ ++ const CMIUtilString &rText(utilValue.GetChildValueCString()); ++ if (rText.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ if (utilValue.IsValueUnknown()) ++ { ++ const CMICmnMIValueConst miValueConst(rText); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ // Note code that has const in will not show the text suffix to the string pointer ++ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this ++ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ } ++ break; + } ++ default: ++ break; + } + return vwrMiValueList.Add(miValueTuple); + } +@@ -863,30 +900,62 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else + { +- // Build parent child composite types +- CMICmnMIValueList miValueList(true); +- for (MIuint i = 0; bOk && (i < nChildren); i++) ++ switch (veVarInfoFormat) + { +- lldb::SBValue member = rValue.GetChildAtIndex(i); +- bOk = GetVariableInfo(vnMaxDepth, member, true, miValueList, ++vrwnDepth); ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ // Build parent child composite types ++ CMICmnMIValueList miValueList(true); ++ for (MIuint i = 0; bOk && (i < nChildren); i++) ++ { ++ lldb::SBValue member = rValue.GetChildAtIndex(i); ++ bOk = GetVariableInfo(vnMaxDepth, member, true, veVarInfoFormat, miValueList, ++vrwnDepth); ++ } ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; + } +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); + } + } +@@ -900,6 +969,7 @@ + // vrValue - (R) LLDB value object. + // vbIsChildValue - (R) True = Value object is a child of a higher Value object, + // - False = Value object not a child. ++// veVarInfoFormat - (R) The type of variable info that should be shown. + // vwrMIValueList - (W) MI value list object. + // vnDepth - (RW) The current recursive depth of this function. + // // Return: MIstatus::success - Functional succeeded. +@@ -908,7 +978,8 @@ + //-- + bool + CMICmnLLDBDebugSessionInfo::GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth) ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, ++ MIuint &vrwnDepth) + { + // *** Update GetVariableInfo() with any code changes here *** + +@@ -935,64 +1006,112 @@ + else + { + // Basic types +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); ++ switch (veVarInfoFormat) ++ { ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; ++ } + return vwrMiValueList.Add(miValueTuple); + } + } + else if (utilValue.IsChildCharType()) + { +- // Append string text to the parent value information +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- +- const CMIUtilString &rText(utilValue.GetChildValueCString()); +- if (rText.empty()) ++ switch (veVarInfoFormat) + { +- const CMICmnMIValueConst miValueConst(utilValue.GetValue()); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); +- } +- else +- { +- if (utilValue.IsValueUnknown()) ++ case eVariableInfoFormat_NoValues: + { +- const CMICmnMIValueConst miValueConst(rText); +- const CMICmnMIValueResult miValueResult("value", miValueConst); +- miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); + } +- else ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: + { +- // Note code that has const in will not show the text suffix to the string pointer +- // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this +- // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this +- const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); +- const CMICmnMIValueResult miValueResult("value", miValueConst); ++ // Append string text to the parent value information ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); + miValueTuple.Add(miValueResult); ++ ++ const CMIUtilString &rText(utilValue.GetChildValueCString()); ++ if (rText.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetValue()); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ if (utilValue.IsValueUnknown()) ++ { ++ const CMICmnMIValueConst miValueConst(rText); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ else ++ { ++ // Note code that has const in will not show the text suffix to the string pointer ++ // i.e. const char * pMyStr = "blah"; ==> "0x00007000"" <-- Eclipse shows this ++ // but char * pMyStr = "blah"; ==> "0x00007000" "blah"" <-- Eclipse shows this ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%s %s", utilValue.GetValue().c_str(), rText.c_str())); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ miValueTuple.Add(miValueResult); ++ } ++ } ++ break; + } ++ default: ++ break; + } + return vwrMiValueList.Add(miValueTuple); + } + else + { +- // Build parent child composite types +- CMICmnMIValueList miValueList(true); +- for (MIuint i = 0; bOk && (i < nChildren); i++) ++ switch (veVarInfoFormat) + { +- lldb::SBValue member = rValue.GetChildAtIndex(i); +- bOk = GetVariableInfo(vnMaxDepth, member, true, miValueList, ++vrwnDepth); ++ case eVariableInfoFormat_NoValues: ++ { ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ return vwrMiValueList.Add(miValueResult); ++ } ++ case eVariableInfoFormat_AllValues: ++ case eVariableInfoFormat_SimpleValues: ++ { ++ // Build parent child composite types ++ CMICmnMIValueList miValueList(true); ++ for (MIuint i = 0; bOk && (i < nChildren); i++) ++ { ++ lldb::SBValue member = rValue.GetChildAtIndex(i); ++ bOk = GetVariableInfo(vnMaxDepth, member, true, veVarInfoFormat, miValueList, ++vrwnDepth); ++ } ++ const CMICmnMIValueConst miValueConst(utilValue.GetName()); ++ const CMICmnMIValueResult miValueResult("name", miValueConst); ++ miValueTuple.Add(miValueResult); ++ const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); ++ const CMICmnMIValueResult miValueResult2("value", miValueConst2); ++ miValueTuple.Add(miValueResult2); ++ break; ++ } ++ default: ++ break; + } +- const CMICmnMIValueConst miValueConst(utilValue.GetName()); +- const CMICmnMIValueResult miValueResult("name", miValueConst); +- miValueTuple.Add(miValueResult); +- const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("{%s}", miValueList.ExtractContentNoBrackets().c_str())); +- const CMICmnMIValueResult miValueResult2("value", miValueConst2); +- miValueTuple.Add(miValueResult2); + return vwrMiValueList.Add(miValueTuple); + } + } +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -117,6 +117,17 @@ + eVariableType_Arguments = (1u << 3) // Arguments. + }; + ++ //++ =================================================================== ++ // Details: Determine the information that should be shown by using MIResponseFormVariableInfo family functions. ++ //-- ++ enum VariableInfoFormat_e ++ { ++ eVariableInfoFormat_NoValues, ++ eVariableInfoFormat_AllValues, ++ eVariableInfoFormat_SimpleValues, ++ kNumVariableInfoFormats ++ }; ++ + // Typedefs: + public: + typedef std::vector VecActiveThreadId_t; +@@ -148,9 +159,12 @@ + bool MIResponseFormThreadInfo(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); + bool MIResponseFormThreadInfo2(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); + bool MIResponseFormThreadInfo3(const SMICmdData &vCmdData, const lldb::SBThread &vrThread, CMICmnMIValueTuple &vwrMIValueTuple); +- bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); +- bool MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); +- bool MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo2(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); ++ bool MIResponseFormVariableInfo3(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList); + bool MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); + bool MIResponseFormBrkPtInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); + bool GetBrkPtInfo(const lldb::SBBreakpoint &vBrkPt, SBrkPtInfo &vrwBrkPtInfo) const; +@@ -188,9 +202,9 @@ + void operator=(const CMICmnLLDBDebugSessionInfo &); + // + bool GetVariableInfo(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); + bool GetVariableInfo2(const MIuint vnMaxDepth, const lldb::SBValue &vrValue, const bool vbIsChildValue, +- CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); ++ const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, MIuint &vrwnDepth); + + // Overridden: + private: +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228386) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -1081,7 +1081,7 @@ + { + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList); ++ bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList); + + CMICmnMIValueTuple miValueTuple; + bOk = bOk && rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple); +@@ -1157,7 +1157,7 @@ + // Function args + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; +- if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) ++ if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues, miValueList)) + return MIstatus::failure; + CMICmnMIValueTuple miValueTuple; + if (!rSession.MIResponseFormFrameInfo2(pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple)) +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 228386) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -254,6 +254,7 @@ + {IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK, "Command '%s'. LLDB unable to read entire memory block of %u bytes at address 0x%08x"}, + {IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to read memory block of %u bytes at address 0x%08x: %s "}, + {IDS_CMD_ERR_INVALID_PROCESS, "Command '%s'. Invalid process during debug session"}, ++ {IDS_CMD_ERR_INVALID_PRINT_VALUES, "Command '%s'. Unknown value for PRINT_VALUES: must be: 0 or \"--no-values\", 1 or \"all-values\", 2 or \"simple-values\""}, + {IDS_CMD_ERR_INVALID_FORMAT_TYPE, "Command '%s'. Invalid var format type '%s'"}, + {IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND, "Command '%s'. Breakpoint information for breakpoint ID %d not found"}, + {IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, "Command '%s'. Unable to write memory block of %u bytes at address 0x%08x: %s "}, +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 228386) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -270,6 +270,7 @@ + IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK, + IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES, + IDS_CMD_ERR_INVALID_PROCESS, ++ IDS_CMD_ERR_INVALID_PRINT_VALUES, + IDS_CMD_ERR_INVALID_FORMAT_TYPE, + IDS_CMD_ERR_BRKPT_INFO_OBJ_NOT_FOUND, + IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES, Index: patches/lldbmi_gdb_set_show_test.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_show_test.patch @@ -0,0 +1,158 @@ +Index: test/tools/lldb-mi/TestMiGdbSetShow.py +=================================================================== +--- test/tools/lldb-mi/TestMiGdbSetShow.py (revision 0) ++++ test/tools/lldb-mi/TestMiGdbSetShow.py (working copy) +@@ -0,0 +1,153 @@ ++""" ++Test that the lldb-mi driver works with '-gdb-set' and '-gdb-show' commands. ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiGdbSetShowTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ def test_lldbmi_targetasync_default(self): ++ """Test that 'lldb-mi --interpreter' in async mode by default.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ def test_lldbmi_targetasync_on(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in async mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async on") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ child.expect("\*running") ++ child.expect("~\"argc=1") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ def test_lldbmi_targetasync_off(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in sync mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async off") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"off\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ ++ # "\*running" is async notification ++ unexpected = [ "\*running" ] ++ it = child.expect(unexpected + [ "~\"argc=1" ]) ++ if it != len(unexpected): ++ # generate error if it's not "~\"argc=1" ++ child.expect("$UNEXPECTED FOUND: %s.^" % (unexpected[it])) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() Index: patches/lldbmi_gdb_set_show_test.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_show_test.v2.patch @@ -0,0 +1,231 @@ +Index: test/tools/lldb-mi/TestMiGdbSetShow.py +=================================================================== +--- test/tools/lldb-mi/TestMiGdbSetShow.py (revision 0) ++++ test/tools/lldb-mi/TestMiGdbSetShow.py (working copy) +@@ -0,0 +1,226 @@ ++""" ++Test that the lldb-mi driver works with '-gdb-set' and '-gdb-show' commands. ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiGdbSetShowTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_default(self): ++ """Test that 'lldb-mi --interpreter' in async mode by default.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_on(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in async mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async on") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ child.expect("\*running") ++ child.expect("~\"argc=1") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_off(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in sync mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async off") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"off\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ ++ # "\*running" is async notification ++ unexpected = [ "\*running" ] ++ it = child.expect(unexpected + [ "~\"argc=1" ]) ++ if it != len(unexpected): ++ # generate error if it's not "~\"argc=1" ++ child.expect("$UNEXPECTED FOUND: %s.^" % (unexpected[it])) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.expectedFailure("-gdb-set ignores unknown properties") ++ @lldbmi_test ++ def test_lldbmi_set_unknown(self): ++ """Test that 'lldb-mi --interpreter' fails when setting an unknown property.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set unknown") ++ child.expect("\^errpr") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.expectedFailure("-gdb-show ignores unknown properties") ++ @lldbmi_test ++ def test_lldbmi_show_unknown(self): ++ """Test that 'lldb-mi --interpreter' fails when showing an unknown property.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-show unknown") ++ child.expect("\^errpr") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() Index: patches/lldbmi_gdb_set_show_test.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_show_test.v3.patch @@ -0,0 +1,231 @@ +Index: test/tools/lldb-mi/TestMiGdbSetShow.py +=================================================================== +--- test/tools/lldb-mi/TestMiGdbSetShow.py (revision 0) ++++ test/tools/lldb-mi/TestMiGdbSetShow.py (working copy) +@@ -0,0 +1,226 @@ ++""" ++Test that the lldb-mi driver works with '-gdb-set' and '-gdb-show' commands. ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiGdbSetShowTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_default(self): ++ """Test that 'lldb-mi --interpreter' in async mode by default.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_on(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in async mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async on") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"on\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ child.expect("\*running") ++ child.expect("~\"argc=1") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_targetasync_off(self): ++ """Test that 'lldb-mi --interpreter' can execute commands in sync mode.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set target-async off") ++ child.expect("\^done") ++ ++ child.sendline("-gdb-show target-async") ++ child.expect("\^done,value=\"off\"") ++ ++ child.sendline("-file-exec-and-symbols %s" % self.myexe) ++ child.expect("\^done") ++ ++ child.sendline("-exec-run") ++ ++ # "\*running" is async notification ++ unexpected = [ "\*running" ] ++ it = child.expect(unexpected + [ "~\"argc=1" ]) ++ if it != len(unexpected): ++ # generate error if it's not "~\"argc=1" ++ child.expect("$UNEXPECTED FOUND: %s.^" % (unexpected[it])) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.expectedFailure("-gdb-set ignores unknown properties") ++ @lldbmi_test ++ def test_lldbmi_set_unknown(self): ++ """Test that 'lldb-mi --interpreter' fails when setting an unknown property.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-set unknown") ++ child.expect("\^error") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @unittest2.expectedFailure("-gdb-show ignores unknown properties") ++ @lldbmi_test ++ def test_lldbmi_show_unknown(self): ++ """Test that 'lldb-mi --interpreter' fails when showing an unknown property.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ child.sendline("-gdb-show unknown") ++ child.expect("\^error") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() Index: patches/lldbmi_gdb_set_targetasync_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_targetasync_support.patch @@ -0,0 +1,86 @@ +Index: tools/lldb-mi/MICmdCmdGdbSet.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.cpp (revision 224200) ++++ tools/lldb-mi/MICmdCmdGdbSet.cpp (working copy) +@@ -30,7 +30,7 @@ + + // Instantiations: + const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = { +- // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options ++ { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, + // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options + {"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath}, + {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}}; +@@ -215,6 +215,36 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB set option 'target-async' to prepare ++// and send back information asked for. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ const bool bEmptyArg(vrWords.empty()); ++ const bool bArgOn(bEmptyArg || CMIUtilString::Compare(vrWords[0], "on")); ++ const bool bArgOff(!bEmptyArg && CMIUtilString::Compare(vrWords[0], "off")); ++ if (!bArgOn && !bArgOff) ++ { ++ m_bGbbOptionFnHasError = true; ++ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC); ++ return MIstatus::failure; ++ } ++ ++ // Turn on/off async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = bArgOn; ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncMode); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare + // and send back information asked for. + // Type: Method. +Index: tools/lldb-mi/MICmdCmdGdbSet.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.h (revision 224200) ++++ tools/lldb-mi/MICmdCmdGdbSet.h (working copy) +@@ -79,6 +79,7 @@ + // Methods: + private: + bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); + bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); + bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); + +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 224200) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -261,6 +261,7 @@ + {IDS_CMD_ERR_SET_NEW_DRIVER_STATE, "Command '%s'. Command tried to set new MI Driver running state and failed. %s"}, + {IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, "The request '%s' was not recogised, not implemented"}, + {IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed."}, ++ {IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, "'target-async' expects \"on\" or \"off\""}, + {IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument"}}; + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 224200) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -277,6 +277,7 @@ + IDS_CMD_ERR_SET_NEW_DRIVER_STATE, + IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, + IDS_CMD_ERR_INFO_PRINTFN_FAILED, ++ IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, + IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH + }; + Index: patches/lldbmi_gdb_set_targetasync_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_targetasync_support.v2.patch @@ -0,0 +1,98 @@ +Index: tools/lldb-mi/MICmdCmdGdbSet.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.cpp (revision 224519) ++++ tools/lldb-mi/MICmdCmdGdbSet.cpp (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.cpp ------- -------------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.cpp --------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -30,7 +30,7 @@ + + // Instantiations: + const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = { +- // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options ++ {"target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync}, + // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options + {"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath}, + {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}}; +@@ -215,6 +215,36 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB set option 'target-async' to prepare ++// and send back information asked for. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ const bool bEmptyArg(vrWords.empty()); ++ const bool bArgOn(bEmptyArg || CMIUtilString::Compare(vrWords[0], "on")); ++ const bool bArgOff(!bEmptyArg && CMIUtilString::Compare(vrWords[0], "off")); ++ if (!bArgOn && !bArgOff) ++ { ++ m_bGbbOptionFnHasError = true; ++ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC); ++ return MIstatus::failure; ++ } ++ ++ // Turn on/off async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = bArgOn; ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncMode); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare + // and send back information asked for. + // Type: Method. +Index: tools/lldb-mi/MICmdCmdGdbSet.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.h (revision 224519) ++++ tools/lldb-mi/MICmdCmdGdbSet.h (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.h ------------- ---------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.h ----------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -79,6 +79,7 @@ + // Methods: + private: + bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); + bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); + bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); + +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 224519) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -261,6 +261,7 @@ + {IDS_CMD_ERR_SET_NEW_DRIVER_STATE, "Command '%s'. Command tried to set new MI Driver running state and failed. %s"}, + {IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, "The request '%s' was not recogised, not implemented"}, + {IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed."}, ++ {IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, "'target-async' expects \"on\" or \"off\""}, + {IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument"}}; + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 224519) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -277,6 +277,7 @@ + IDS_CMD_ERR_SET_NEW_DRIVER_STATE, + IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, + IDS_CMD_ERR_INFO_PRINTFN_FAILED, ++ IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, + IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH + }; + Index: patches/lldbmi_gdb_set_targetasync_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_targetasync_support.v3.patch @@ -0,0 +1,112 @@ +Index: tools/lldb-mi/MICmdCmdGdbSet.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.cpp (revision 225612) ++++ tools/lldb-mi/MICmdCmdGdbSet.cpp (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.cpp ------- -------------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.cpp --------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -30,7 +30,7 @@ + + // Instantiations: + const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = { +- // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options ++ {"target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync}, + // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options + {"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath}, + {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}}; +@@ -215,6 +215,50 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB set option 'target-async' to prepare ++// and send back information asked for. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ bool bAsyncMode; ++ bool bOk = true; ++ ++ if (vrWords.size() > 1) ++ // Too many arguments. ++ bOk = false; ++ else if (vrWords.size() == 0) ++ // If no arguments, default is "on". ++ bAsyncMode = true; ++ else if (CMIUtilString::Compare(vrWords[0], "on")) ++ bAsyncMode = true; ++ else if (CMIUtilString::Compare(vrWords[0], "off")) ++ bAsyncMode = false; ++ else ++ // Unrecognized argument. ++ bOk = false; ++ ++ if (!bOk) ++ { ++ // Report error. ++ m_bGbbOptionFnHasError = true; ++ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC); ++ return MIstatus::failure; ++ } ++ ++ // Turn async mode on/off. ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncMode); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare + // and send back information asked for. + // Type: Method. +Index: tools/lldb-mi/MICmdCmdGdbSet.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.h (revision 225612) ++++ tools/lldb-mi/MICmdCmdGdbSet.h (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.h ------------- ---------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.h ----------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -79,6 +79,7 @@ + // Methods: + private: + bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); + bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); + bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); + +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 225612) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -261,6 +261,7 @@ + {IDS_CMD_ERR_SET_NEW_DRIVER_STATE, "Command '%s'. Command tried to set new MI Driver running state and failed. %s"}, + {IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, "The request '%s' was not recogised, not implemented"}, + {IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed."}, ++ {IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, "'target-async' expects \"on\" or \"off\""}, + {IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument"}}; + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 225612) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -277,6 +277,7 @@ + IDS_CMD_ERR_SET_NEW_DRIVER_STATE, + IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, + IDS_CMD_ERR_INFO_PRINTFN_FAILED, ++ IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, + IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH + }; + Index: patches/lldbmi_gdb_set_targetasync_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_set_targetasync_support.v4.patch @@ -0,0 +1,187 @@ +Index: tools/lldb-mi/MICmdCmdGdbSet.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.cpp (revision 226488) ++++ tools/lldb-mi/MICmdCmdGdbSet.cpp (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.cpp ------- -------------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.cpp --------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -30,7 +30,7 @@ + + // Instantiations: + const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = { +- // { "target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync }, // Example code if need to implement GDB set other options ++ {"target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync}, + // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd }, // Example code if need to implement GDB set other options + {"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath}, + {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}}; +@@ -89,7 +89,7 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: The invoker requires this function. The command does work in this function. ++// Details: The invoker requires this function. The command is executed in this function. + // The command is likely to communicate with the LLDB SBDebugger in here. + // Type: Overridden. + // Args: None. +@@ -142,7 +142,7 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: The invoker requires this function. The command prepares a MI Record Result +-// for the work carried out in the Execute(). ++// for the work carried out in the Execute() method. + // Type: Overridden. + // Args: None. + // Return: MIstatus::success - Functional succeeded. +@@ -152,6 +152,8 @@ + bool + CMICmdCmdGdbSet::Acknowledge(void) + { ++ // Print error if option isn't recognized: ++ // ^error,msg="The request '%s' was not recognized, not implemented" + if (!m_bGdbOptionRecognised) + { + const CMICmnMIValueConst miValueConst( +@@ -162,6 +164,7 @@ + return MIstatus::success; + } + ++ // ^done,value="%s" + if (m_bGdbOptionFnSuccessful) + { + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); +@@ -169,6 +172,8 @@ + return MIstatus::success; + } + ++ // Print error if request failed: ++ // ^error,msg="The request '%s' failed. + const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str())); + const CMICmnMIValueResult miValueResult("msg", miValueConst); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); +@@ -215,6 +220,50 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB set option 'target-async' to prepare ++// and send back information asked for. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ bool bAsyncMode; ++ bool bOk = true; ++ ++ if (vrWords.size() > 1) ++ // Too many arguments. ++ bOk = false; ++ else if (vrWords.size() == 0) ++ // If no arguments, default is "on". ++ bAsyncMode = true; ++ else if (CMIUtilString::Compare(vrWords[0], "on")) ++ bAsyncMode = true; ++ else if (CMIUtilString::Compare(vrWords[0], "off")) ++ bAsyncMode = false; ++ else ++ // Unrecognized argument. ++ bOk = false; ++ ++ if (!bOk) ++ { ++ // Report error. ++ m_bGbbOptionFnHasError = true; ++ m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC); ++ return MIstatus::failure; ++ } ++ ++ // Turn async mode on/off. ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncMode); ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare + // and send back information asked for. + // Type: Method. +@@ -248,8 +297,8 @@ + } + + //++ ------------------------------------------------------------------------------------ +-// Details: Carry out work to complete the GDB set option to prepare and send back information +-// asked for. ++// Details: Carry out work to complete the GDB set option to prepare and send back the ++// requested information. + // Type: Method. + // Args: None. + // Return: MIstatus::success - Functional succeeded. +@@ -261,8 +310,8 @@ + { + MIunused(vrWords); + +- // Do nothing - intentional. This is a fallback temporary action function to do nothing. +- // This allows the search for gdb-set options to always suceed when the option is not ++ // Do nothing - intentional. This is a fallback function to do nothing. ++ // This allows the search for gdb-show options to always succeed when the option is not + // found (implemented). + + return MIstatus::success; +Index: tools/lldb-mi/MICmdCmdGdbSet.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbSet.h (revision 226488) ++++ tools/lldb-mi/MICmdCmdGdbSet.h (working copy) +@@ -1,4 +1,4 @@ +-//===-- MICmdCmdGdbSet.h ------------- ---------------------*- C++ -*-===// ++//===-- MICmdCmdGdbSet.h ----------------------------------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // +@@ -12,7 +12,7 @@ + // + // Overview: CMICmdCmdGdbSet interface. + // +-// To implement new MI commands derive a new command class from the command base ++// To implement new MI commands, derive a new command class from the command base + // class. To enable the new command for interpretation add the new command class + // to the command factory. The files of relevance are: + // MICmdCommands.cpp +@@ -79,6 +79,7 @@ + // Methods: + private: + bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); + bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); + bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); + +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 226488) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -261,6 +261,7 @@ + {IDS_CMD_ERR_SET_NEW_DRIVER_STATE, "Command '%s'. Command tried to set new MI Driver running state and failed. %s"}, + {IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, "The request '%s' was not recogised, not implemented"}, + {IDS_CMD_ERR_INFO_PRINTFN_FAILED, "The request '%s' failed."}, ++ {IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, "'target-async' expects \"on\" or \"off\""}, + {IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH, "'solib-search-path' requires at least one argument"}}; + + //++ ------------------------------------------------------------------------------------ +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 226488) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -277,6 +277,7 @@ + IDS_CMD_ERR_SET_NEW_DRIVER_STATE, + IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND, + IDS_CMD_ERR_INFO_PRINTFN_FAILED, ++ IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC, + IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH + }; + Index: patches/lldbmi_gdb_show_targetasync_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_show_targetasync_support.patch @@ -0,0 +1,413 @@ +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 224519) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -37,6 +37,7 @@ + #include "MICmdCmdFile.h" + #include "MICmdCmdGdbInfo.h" + #include "MICmdCmdGdbSet.h" ++#include "MICmdCmdGdbShow.h" + #include "MICmdCmdGdbThread.h" + #include "MICmdCmdMiscellanous.h" + #include "MICmdCmdStack.h" +@@ -110,6 +111,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); +Index: tools/lldb-mi/MICmdCmdGdbShow.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.h (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.h (working copy) +@@ -0,0 +1,98 @@ ++//===-- MICmdCmdGdbShow.h ---------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.h ++// ++// Overview: CMICmdCmdGdbShow interface. ++// ++// To implement new MI commands derive a new command class from the command base ++// class. To enable the new command for interpretation add the new command class ++// to the command factory. The files of relevance are: ++// MICmdCommands.cpp ++// MICmdBase.h / .cpp ++// MICmdCmd.h / .cpp ++// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery ++// command class as an example. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// In-house headers: ++#include "MICmdBase.h" ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "gdb-set". ++// This command does not follow the MI documentation exactly. While *this ++// command is implemented it does not do anything with the gdb-set ++// variable past in. ++// The design of matching the info request to a request action (or ++// command) is very simple. The request function which carries out ++// the task of information gathering and printing to stdout is part of ++// *this class. Should the request function become more complicated then ++// that request should really reside in a command type class. Then this ++// class instantiates a request info command for a matching request. The ++// design/code of *this class then does not then become bloated. Use a ++// lightweight version of the current MI command system. ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 18/12/2014. ++// Changes: None. ++//-- ++class CMICmdCmdGdbShow : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdGdbShow(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdGdbShow(void); ++ ++ // Typedefs: ++ private: ++ typedef bool (CMICmdCmdGdbShow::*FnGdbOptionPtr)(const CMIUtilString::VecString_t &vrWords); ++ typedef std::map MapGdbOptionNameToFnGdbOptionPtr_t; ++ ++ // Methods: ++ private: ++ bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); ++ ++ // Attributes: ++ private: ++ const static MapGdbOptionNameToFnGdbOptionPtr_t ms_mapGdbOptionNameToFnGdbOptionPtr; ++ // ++ const CMIUtilString m_constStrArgNamedThreadGrp; ++ const CMIUtilString m_constStrArgNamedGdbOption; ++ bool m_bGdbOptionRecognised; // True = This command has a function with a name that matches the Print argument, false = not found ++ bool m_bGdbOptionFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason ++ bool m_bGbbOptionFnHasError; // True = The option function has an error condition (not the command!), false = option function ok. ++ CMIUtilString m_strGdbOptionName; ++ CMIUtilString m_strGdbOptionFnError; ++ CMIUtilString m_strValue; ++}; +Index: tools/lldb-mi/MICmdCmdGdbShow.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.cpp (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.cpp (working copy) +@@ -0,0 +1,265 @@ ++//===-- MICmdCmdGdbShow.cpp -------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.cpp ++// ++// Overview: CMICmdCmdGdbShow implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// In-house headers: ++#include "MICmdCmdGdbShow.h" ++#include "MICmnMIResultRecord.h" ++#include "MICmnMIValueConst.h" ++#include "MICmdArgValString.h" ++#include "MICmdArgValListOfN.h" ++#include "MICmdArgValOptionLong.h" ++#include "MICmnLLDBDebugSessionInfo.h" ++ ++// Instantiations: ++const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbShow::ms_mapGdbOptionNameToFnGdbOptionPtr = { ++ {"target-async", &CMICmdCmdGdbShow::OptionFnTargetAsync}, ++ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}}; ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::CMICmdCmdGdbShow(void) ++ : m_constStrArgNamedThreadGrp("thread-group") ++ , m_constStrArgNamedGdbOption("option") ++ , m_bGdbOptionRecognised(true) ++ , m_bGdbOptionFnSuccessful(false) ++ , m_bGbbOptionFnHasError(false) ++ , m_strGdbOptionFnError(MIRSRC(IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS)) ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "gdb-show"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdGdbShow::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::~CMICmdCmdGdbShow(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValOptionLong(m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1))); ++ bOk = bOk && ++ m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgNamedGdbOption, false, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command does work in this function. ++// The command is likely to communicate with the LLDB SBDebugger in here. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption); ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions()); ++ ++ // Get the gdb-show option to carry out ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin(); ++ const CMICmdArgValString *pOption = static_cast(*it); ++ const CMIUtilString strOption(pOption->GetValue()); ++ ++it; ++ ++ // Retrieve the parameter(s) for the option ++ CMIUtilString::VecString_t vecWords; ++ while (it != rVecWords.end()) ++ { ++ const CMICmdArgValString *pWord = static_cast(*it); ++ vecWords.push_back(pWord->GetValue()); ++ ++ // Next ++ ++it; ++ } ++ ++ FnGdbOptionPtr pPrintRequestFn = nullptr; ++ if (!GetOptionFn(strOption, pPrintRequestFn)) ++ { ++ // For unimplemented option handlers, fallback on a generic handler ++ // ToDo: Remove this when ALL options have been implemented ++ if (!GetOptionFn("fallback", pPrintRequestFn)) ++ { ++ m_bGdbOptionRecognised = false; ++ m_strGdbOptionName = "fallback"; // This would be the strOption name ++ return MIstatus::success; ++ } ++ } ++ ++ m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))(vecWords); ++ if (!m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError) ++ return MIstatus::failure; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute(). ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Acknowledge(void) ++{ ++ if (!m_bGdbOptionRecognised) ++ { ++ const CMICmnMIValueConst miValueConst( ++ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND), m_strGdbOptionName.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ if (m_bGdbOptionFnSuccessful && !m_strValue.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(m_strValue); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ else if (m_bGdbOptionFnSuccessful) ++ { ++ // Ignore empty value (for fallback) ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdGdbShow::CreateSelf(void) ++{ ++ return new CMICmdCmdGdbShow(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Retrieve the print function's pointer for the matching print request. ++// Type: Method. ++// Args: vrPrintFnName - (R) The info requested. ++// vrwpFn - (W) The print function's pointer of the function to carry out ++// Return: bool - True = Print request is implemented, false = not found. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr &vrwpFn) const ++{ ++ vrwpFn = nullptr; ++ ++ const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find(vrPrintFnName); ++ if (it != ms_mapGdbOptionNameToFnGdbOptionPtr.end()) ++ { ++ vrwpFn = (*it).second; ++ return true; ++ } ++ ++ return false; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option 'target-async' to prepare ++// and send back information asked for. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Get async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ ++ m_strValue = bAsyncMode ? "on" : "off"; ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option to prepare and send back information ++// asked for. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnFallback(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Do nothing - intentional. This is a fallback temporary action function to do nothing. ++ // This allows the search for gdb-show options to always suceed when the option is not ++ // found (implemented). ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 224519) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -25,6 +25,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +@@ -106,6 +107,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp Index: patches/lldbmi_gdb_show_targetasync_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_show_targetasync_support.v2.patch @@ -0,0 +1,417 @@ +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 225612) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -25,6 +25,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +@@ -106,6 +107,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +Index: tools/lldb-mi/MICmdCmdGdbShow.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.cpp (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.cpp (working copy) +@@ -0,0 +1,269 @@ ++//===-- MICmdCmdGdbShow.cpp -------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.cpp ++// ++// Overview: CMICmdCmdGdbShow implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// In-house headers: ++#include "MICmdCmdGdbShow.h" ++#include "MICmnMIResultRecord.h" ++#include "MICmnMIValueConst.h" ++#include "MICmdArgValString.h" ++#include "MICmdArgValListOfN.h" ++#include "MICmdArgValOptionLong.h" ++#include "MICmnLLDBDebugSessionInfo.h" ++ ++// Instantiations: ++const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbShow::ms_mapGdbOptionNameToFnGdbOptionPtr = { ++ {"target-async", &CMICmdCmdGdbShow::OptionFnTargetAsync}, ++ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}}; ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::CMICmdCmdGdbShow(void) ++ : m_constStrArgNamedThreadGrp("thread-group") ++ , m_constStrArgNamedGdbOption("option") ++ , m_bGdbOptionRecognised(true) ++ , m_bGdbOptionFnSuccessful(false) ++ , m_bGbbOptionFnHasError(false) ++ , m_strGdbOptionFnError(MIRSRC(IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS)) ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "gdb-show"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdGdbShow::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::~CMICmdCmdGdbShow(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValOptionLong(m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1))); ++ bOk = bOk && ++ m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgNamedGdbOption, true, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command is executed in this function. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption); ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions()); ++ ++ // Get the gdb-show option to carry out ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin(); ++ const CMICmdArgValString *pOption = static_cast(*it); ++ const CMIUtilString strOption(pOption->GetValue()); ++ ++it; ++ ++ // Retrieve the parameter(s) for the option ++ CMIUtilString::VecString_t vecWords; ++ while (it != rVecWords.end()) ++ { ++ const CMICmdArgValString *pWord = static_cast(*it); ++ vecWords.push_back(pWord->GetValue()); ++ ++ // Next ++ ++it; ++ } ++ ++ FnGdbOptionPtr pPrintRequestFn = nullptr; ++ if (!GetOptionFn(strOption, pPrintRequestFn)) ++ { ++ // For unimplemented option handlers, fallback on a generic handler ++ // ToDo: Remove this when ALL options have been implemented ++ if (!GetOptionFn("fallback", pPrintRequestFn)) ++ { ++ m_bGdbOptionRecognised = false; ++ m_strGdbOptionName = "fallback"; // This would be the strOption name ++ return MIstatus::success; ++ } ++ } ++ ++ m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))(vecWords); ++ if (!m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError) ++ return MIstatus::failure; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute() method. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Acknowledge(void) ++{ ++ // Print error if option doesn't recognised: ++ // ^error,msg="The request '%s' was not recogised, not implemented" ++ if (!m_bGdbOptionRecognised) ++ { ++ const CMICmnMIValueConst miValueConst( ++ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND), m_strGdbOptionName.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // ^done,value="%s" ++ if (m_bGdbOptionFnSuccessful && !m_strValue.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(m_strValue); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ else if (m_bGdbOptionFnSuccessful) ++ { ++ // Ignore empty value (for fallback) ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // Print error if request failed: ++ // ^error,msg="The request '%s' failed. ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdGdbShow::CreateSelf(void) ++{ ++ return new CMICmdCmdGdbShow(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Retrieve the print function's pointer for the matching print request. ++// Type: Method. ++// Args: vrPrintFnName - (R) The info requested. ++// vrwpFn - (W) The print function's pointer of the function to carry out ++// Return: bool - True = Print request is implemented, false = not found. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr &vrwpFn) const ++{ ++ vrwpFn = nullptr; ++ ++ const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find(vrPrintFnName); ++ if (it != ms_mapGdbOptionNameToFnGdbOptionPtr.end()) ++ { ++ vrwpFn = (*it).second; ++ return true; ++ } ++ ++ return false; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option 'target-async' to prepare ++// and send back the requested information. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Get async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ ++ m_strValue = bAsyncMode ? "on" : "off"; ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option to prepare and send back the ++// requested information. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnFallback(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Do nothing - intentional. This is a fallback function to do nothing. ++ // This allows the search for gdb-show options to always succeed when the option is not ++ // found (implemented). ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/MICmdCmdGdbShow.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.h (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.h (working copy) +@@ -0,0 +1,98 @@ ++//===-- MICmdCmdGdbShow.h ---------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.h ++// ++// Overview: CMICmdCmdGdbShow interface. ++// ++// To implement new MI commands derive a new command class from the command base ++// class. To enable the new command for interpretation add the new command class ++// to the command factory. The files of relevance are: ++// MICmdCommands.cpp ++// MICmdBase.h / .cpp ++// MICmdCmd.h / .cpp ++// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery ++// command class as an example. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// In-house headers: ++#include "MICmdBase.h" ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "gdb-set". ++// This command does not follow the MI documentation exactly. While *this ++// command is implemented it does not do anything with the gdb-set ++// variable past in. ++// The design of matching the info request to a request action (or ++// command) is very simple. The request function which carries out ++// the task of information gathering and printing to stdout is part of ++// *this class. Should the request function become more complicated then ++// that request should really reside in a command type class. Then this ++// class instantiates a request info command for a matching request. The ++// design/code of *this class then does not then become bloated. Use a ++// lightweight version of the current MI command system. ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 18/12/2014. ++// Changes: None. ++//-- ++class CMICmdCmdGdbShow : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdGdbShow(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdGdbShow(void); ++ ++ // Typedefs: ++ private: ++ typedef bool (CMICmdCmdGdbShow::*FnGdbOptionPtr)(const CMIUtilString::VecString_t &vrWords); ++ typedef std::map MapGdbOptionNameToFnGdbOptionPtr_t; ++ ++ // Methods: ++ private: ++ bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); ++ ++ // Attributes: ++ private: ++ const static MapGdbOptionNameToFnGdbOptionPtr_t ms_mapGdbOptionNameToFnGdbOptionPtr; ++ // ++ const CMIUtilString m_constStrArgNamedThreadGrp; ++ const CMIUtilString m_constStrArgNamedGdbOption; ++ bool m_bGdbOptionRecognised; // True = This command has a function with a name that matches the Print argument, false = not found ++ bool m_bGdbOptionFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason ++ bool m_bGbbOptionFnHasError; // True = The option function has an error condition (not the command!), false = option function ok. ++ CMIUtilString m_strGdbOptionName; ++ CMIUtilString m_strGdbOptionFnError; ++ CMIUtilString m_strValue; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 225612) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -37,6 +37,7 @@ + #include "MICmdCmdFile.h" + #include "MICmdCmdGdbInfo.h" + #include "MICmdCmdGdbSet.h" ++#include "MICmdCmdGdbShow.h" + #include "MICmdCmdGdbThread.h" + #include "MICmdCmdMiscellanous.h" + #include "MICmdCmdStack.h" +@@ -110,6 +111,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_gdb_show_targetasync_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_show_targetasync_support.v3.patch @@ -0,0 +1,417 @@ +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 226488) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -25,6 +25,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +@@ -106,6 +107,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +Index: tools/lldb-mi/MICmdCmdGdbShow.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.cpp (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.cpp (working copy) +@@ -0,0 +1,269 @@ ++//===-- MICmdCmdGdbShow.cpp -------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.cpp ++// ++// Overview: CMICmdCmdGdbShow implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// In-house headers: ++#include "MICmdCmdGdbShow.h" ++#include "MICmnMIResultRecord.h" ++#include "MICmnMIValueConst.h" ++#include "MICmdArgValString.h" ++#include "MICmdArgValListOfN.h" ++#include "MICmdArgValOptionLong.h" ++#include "MICmnLLDBDebugSessionInfo.h" ++ ++// Instantiations: ++const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbShow::ms_mapGdbOptionNameToFnGdbOptionPtr = { ++ {"target-async", &CMICmdCmdGdbShow::OptionFnTargetAsync}, ++ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}}; ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::CMICmdCmdGdbShow(void) ++ : m_constStrArgNamedThreadGrp("thread-group") ++ , m_constStrArgNamedGdbOption("option") ++ , m_bGdbOptionRecognised(true) ++ , m_bGdbOptionFnSuccessful(false) ++ , m_bGbbOptionFnHasError(false) ++ , m_strGdbOptionFnError(MIRSRC(IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS)) ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "gdb-show"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdGdbShow::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::~CMICmdCmdGdbShow(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValOptionLong(m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1))); ++ bOk = bOk && ++ m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgNamedGdbOption, true, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command is executed in this function. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption); ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions()); ++ ++ // Get the gdb-show option to carry out ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin(); ++ const CMICmdArgValString *pOption = static_cast(*it); ++ const CMIUtilString strOption(pOption->GetValue()); ++ ++it; ++ ++ // Retrieve the parameter(s) for the option ++ CMIUtilString::VecString_t vecWords; ++ while (it != rVecWords.end()) ++ { ++ const CMICmdArgValString *pWord = static_cast(*it); ++ vecWords.push_back(pWord->GetValue()); ++ ++ // Next ++ ++it; ++ } ++ ++ FnGdbOptionPtr pPrintRequestFn = nullptr; ++ if (!GetOptionFn(strOption, pPrintRequestFn)) ++ { ++ // For unimplemented option handlers, fallback on a generic handler ++ // ToDo: Remove this when ALL options have been implemented ++ if (!GetOptionFn("fallback", pPrintRequestFn)) ++ { ++ m_bGdbOptionRecognised = false; ++ m_strGdbOptionName = "fallback"; // This would be the strOption name ++ return MIstatus::success; ++ } ++ } ++ ++ m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))(vecWords); ++ if (!m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError) ++ return MIstatus::failure; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute() method. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Acknowledge(void) ++{ ++ // Print error if option isn't recognized: ++ // ^error,msg="The request '%s' was not recognized, not implemented" ++ if (!m_bGdbOptionRecognised) ++ { ++ const CMICmnMIValueConst miValueConst( ++ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND), m_strGdbOptionName.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // ^done,value="%s" ++ if (m_bGdbOptionFnSuccessful && !m_strValue.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(m_strValue); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ else if (m_bGdbOptionFnSuccessful) ++ { ++ // Ignore empty value (for fallback) ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // Print error if request failed: ++ // ^error,msg="The request '%s' failed. ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdGdbShow::CreateSelf(void) ++{ ++ return new CMICmdCmdGdbShow(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Retrieve the print function's pointer for the matching print request. ++// Type: Method. ++// Args: vrPrintFnName - (R) The info requested. ++// vrwpFn - (W) The print function's pointer of the function to carry out ++// Return: bool - True = Print request is implemented, false = not found. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr &vrwpFn) const ++{ ++ vrwpFn = nullptr; ++ ++ const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find(vrPrintFnName); ++ if (it != ms_mapGdbOptionNameToFnGdbOptionPtr.end()) ++ { ++ vrwpFn = (*it).second; ++ return true; ++ } ++ ++ return false; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option 'target-async' to prepare ++// and send back the requested information. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Get async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ ++ m_strValue = bAsyncMode ? "on" : "off"; ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option to prepare and send back the ++// requested information. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnFallback(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Do nothing - intentional. This is a fallback function to do nothing. ++ // This allows the search for gdb-show options to always succeed when the option is not ++ // found (implemented). ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/MICmdCmdGdbShow.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.h (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.h (working copy) +@@ -0,0 +1,98 @@ ++//===-- MICmdCmdGdbShow.h ---------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.h ++// ++// Overview: CMICmdCmdGdbShow interface. ++// ++// To implement new MI commands, derive a new command class from the command base ++// class. To enable the new command for interpretation add the new command class ++// to the command factory. The files of relevance are: ++// MICmdCommands.cpp ++// MICmdBase.h / .cpp ++// MICmdCmd.h / .cpp ++// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery ++// command class as an example. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// In-house headers: ++#include "MICmdBase.h" ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "gdb-set". ++// This command does not follow the MI documentation exactly. While *this ++// command is implemented it does not do anything with the gdb-set ++// variable past in. ++// The design of matching the info request to a request action (or ++// command) is very simple. The request function which carries out ++// the task of information gathering and printing to stdout is part of ++// *this class. Should the request function become more complicated then ++// that request should really reside in a command type class. Then this ++// class instantiates a request info command for a matching request. The ++// design/code of *this class then does not then become bloated. Use a ++// lightweight version of the current MI command system. ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 18/12/2014. ++// Changes: None. ++//-- ++class CMICmdCmdGdbShow : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdGdbShow(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdGdbShow(void); ++ ++ // Typedefs: ++ private: ++ typedef bool (CMICmdCmdGdbShow::*FnGdbOptionPtr)(const CMIUtilString::VecString_t &vrWords); ++ typedef std::map MapGdbOptionNameToFnGdbOptionPtr_t; ++ ++ // Methods: ++ private: ++ bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); ++ ++ // Attributes: ++ private: ++ const static MapGdbOptionNameToFnGdbOptionPtr_t ms_mapGdbOptionNameToFnGdbOptionPtr; ++ // ++ const CMIUtilString m_constStrArgNamedThreadGrp; ++ const CMIUtilString m_constStrArgNamedGdbOption; ++ bool m_bGdbOptionRecognised; // True = This command has a function with a name that matches the Print argument, false = not found ++ bool m_bGdbOptionFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason ++ bool m_bGbbOptionFnHasError; // True = The option function has an error condition (not the command!), false = option function ok. ++ CMIUtilString m_strGdbOptionName; ++ CMIUtilString m_strGdbOptionFnError; ++ CMIUtilString m_strValue; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 226488) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -37,6 +37,7 @@ + #include "MICmdCmdFile.h" + #include "MICmdCmdGdbInfo.h" + #include "MICmdCmdGdbSet.h" ++#include "MICmdCmdGdbShow.h" + #include "MICmdCmdGdbThread.h" + #include "MICmdCmdMiscellanous.h" + #include "MICmdCmdStack.h" +@@ -110,6 +111,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_gdb_show_targetasync_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_gdb_show_targetasync_support.v4.patch @@ -0,0 +1,416 @@ +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 226488) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -25,6 +25,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +@@ -106,6 +107,7 @@ + MICmdCmdFile.cpp + MICmdCmdGdbInfo.cpp + MICmdCmdGdbSet.cpp ++ MICmdCmdGdbShow.cpp + MICmdCmdGdbThread.cpp + MICmdCmdMiscellanous.cpp + MICmdCmdStack.cpp +Index: tools/lldb-mi/MICmdCmdGdbShow.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.cpp (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.cpp (working copy) +@@ -0,0 +1,269 @@ ++//===-- MICmdCmdGdbShow.cpp -------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.cpp ++// ++// Overview: CMICmdCmdGdbShow implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// In-house headers: ++#include "MICmdCmdGdbShow.h" ++#include "MICmnMIResultRecord.h" ++#include "MICmnMIValueConst.h" ++#include "MICmdArgValString.h" ++#include "MICmdArgValListOfN.h" ++#include "MICmdArgValOptionLong.h" ++#include "MICmnLLDBDebugSessionInfo.h" ++ ++// Instantiations: ++const CMICmdCmdGdbShow::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbShow::ms_mapGdbOptionNameToFnGdbOptionPtr = { ++ {"target-async", &CMICmdCmdGdbShow::OptionFnTargetAsync}, ++ {"fallback", &CMICmdCmdGdbShow::OptionFnFallback}}; ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::CMICmdCmdGdbShow(void) ++ : m_constStrArgNamedThreadGrp("thread-group") ++ , m_constStrArgNamedGdbOption("option") ++ , m_bGdbOptionRecognised(true) ++ , m_bGdbOptionFnSuccessful(false) ++ , m_bGbbOptionFnHasError(false) ++ , m_strGdbOptionFnError(MIRSRC(IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS)) ++{ ++ // Command factory matches this name with that received from the stdin stream ++ m_strMiCmd = "gdb-show"; ++ ++ // Required by the CMICmdFactory when registering *this command ++ m_pSelfCreatorFn = &CMICmdCmdGdbShow::CreateSelf; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmdCmdGdbShow destructor. ++// Type: Overrideable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmdCmdGdbShow::~CMICmdCmdGdbShow(void) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The parses the command line options ++// arguments to extract values for each of those arguments. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::ParseArgs(void) ++{ ++ bool bOk = m_setCmdArgs.Add( ++ *(new CMICmdArgValOptionLong(m_constStrArgNamedThreadGrp, false, false, CMICmdArgValListBase::eArgValType_ThreadGrp, 1))); ++ bOk = bOk && ++ m_setCmdArgs.Add( ++ *(new CMICmdArgValListOfN(m_constStrArgNamedGdbOption, true, true, CMICmdArgValListBase::eArgValType_StringAnything))); ++ return (bOk && ParseValidateCmdOptions()); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command is executed in this function. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Execute(void) ++{ ++ CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption); ++ const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions()); ++ ++ // Get the gdb-show option to carry out ++ CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin(); ++ const CMICmdArgValString *pOption = static_cast(*it); ++ const CMIUtilString strOption(pOption->GetValue()); ++ ++it; ++ ++ // Retrieve the parameter(s) for the option ++ CMIUtilString::VecString_t vecWords; ++ while (it != rVecWords.end()) ++ { ++ const CMICmdArgValString *pWord = static_cast(*it); ++ vecWords.push_back(pWord->GetValue()); ++ ++ // Next ++ ++it; ++ } ++ ++ FnGdbOptionPtr pPrintRequestFn = nullptr; ++ if (!GetOptionFn(strOption, pPrintRequestFn)) ++ { ++ // For unimplemented option handlers, fallback on a generic handler ++ // ToDo: Remove this when ALL options have been implemented ++ if (!GetOptionFn("fallback", pPrintRequestFn)) ++ { ++ m_bGdbOptionRecognised = false; ++ m_strGdbOptionName = "fallback"; // This would be the strOption name ++ return MIstatus::success; ++ } ++ } ++ ++ m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))(vecWords); ++ if (!m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError) ++ return MIstatus::failure; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: The invoker requires this function. The command prepares a MI Record Result ++// for the work carried out in the Execute() method. ++// Type: Overridden. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::Acknowledge(void) ++{ ++ // Print error if option isn't recognized: ++ // ^error,msg="The request '%s' was not recognized, not implemented" ++ if (!m_bGdbOptionRecognised) ++ { ++ const CMICmnMIValueConst miValueConst( ++ CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND), m_strGdbOptionName.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // ^done,value="%s" ++ if (m_bGdbOptionFnSuccessful && !m_strValue.empty()) ++ { ++ const CMICmnMIValueConst miValueConst(m_strValue); ++ const CMICmnMIValueResult miValueResult("value", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ else if (m_bGdbOptionFnSuccessful) ++ { ++ // Ignore empty value (for fallback) ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done); ++ m_miResultRecord = miRecordResult; ++ return MIstatus::success; ++ } ++ ++ // Print error if request failed: ++ // ^error,msg="The request '%s' failed. ++ const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str())); ++ const CMICmnMIValueResult miValueResult("msg", miValueConst); ++ const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult); ++ m_miResultRecord = miRecordResult; ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Required by the CMICmdFactory when registering *this command. The factory ++// calls this function to create an instance of *this command. ++// Type: Static method. ++// Args: None. ++// Return: CMICmdBase * - Pointer to a new command. ++// Throws: None. ++//-- ++CMICmdBase * ++CMICmdCmdGdbShow::CreateSelf(void) ++{ ++ return new CMICmdCmdGdbShow(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Retrieve the print function's pointer for the matching print request. ++// Type: Method. ++// Args: vrPrintFnName - (R) The info requested. ++// vrwpFn - (W) The print function's pointer of the function to carry out ++// Return: bool - True = Print request is implemented, false = not found. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr &vrwpFn) const ++{ ++ vrwpFn = nullptr; ++ ++ const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find(vrPrintFnName); ++ if (it != ms_mapGdbOptionNameToFnGdbOptionPtr.end()) ++ { ++ vrwpFn = (*it).second; ++ return true; ++ } ++ ++ return false; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option 'target-async' to prepare ++// and send back the requested information. ++// Type: Method. ++// Args: vrWords - (R) List of additional parameters used by this option. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Get async mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncMode = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ ++ m_strValue = bAsyncMode ? "on" : "off"; ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Carry out work to complete the GDB show option to prepare and send back the ++// requested information. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Function succeeded. ++// MIstatus::failure - Function failed. ++// Throws: None. ++//-- ++bool ++CMICmdCmdGdbShow::OptionFnFallback(const CMIUtilString::VecString_t &vrWords) ++{ ++ MIunused(vrWords); ++ ++ // Do nothing - intentional. This is a fallback function to do nothing. ++ // This allows the search for gdb-show options to always succeed when the option is not ++ // found (implemented). ++ ++ return MIstatus::success; ++} +Index: tools/lldb-mi/MICmdCmdGdbShow.h +=================================================================== +--- tools/lldb-mi/MICmdCmdGdbShow.h (revision 0) ++++ tools/lldb-mi/MICmdCmdGdbShow.h (working copy) +@@ -0,0 +1,97 @@ ++//===-- MICmdCmdGdbShow.h ---------------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MICmdCmdGdbShow.h ++// ++// Overview: CMICmdCmdGdbShow interface. ++// ++// To implement new MI commands, derive a new command class from the command base ++// class. To enable the new command for interpretation add the new command class ++// to the command factory. The files of relevance are: ++// MICmdCommands.cpp ++// MICmdBase.h / .cpp ++// MICmdCmd.h / .cpp ++// For an introduction to adding a new command see CMICmdCmdSupportInfoMiCmdQuery ++// command class as an example. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// In-house headers: ++#include "MICmdBase.h" ++ ++//++ ============================================================================ ++// Details: MI command class. MI commands derived from the command base class. ++// *this class implements MI command "gdb-set". ++// This command does not follow the MI documentation exactly. While *this ++// command is implemented it does not do anything with the gdb-set ++// variable past in. ++// The design of matching the info request to a request action (or ++// command) is very simple. The request function which carries out ++// the task of information gathering and printing to stdout is part of ++// *this class. Should the request function become more complicated then ++// that request should really reside in a command type class. Then this ++// class instantiates a request info command for a matching request. The ++// design/code of *this class then does not then become bloated. Use a ++// lightweight version of the current MI command system. ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 18/12/2014. ++// Changes: None. ++//-- ++class CMICmdCmdGdbShow : public CMICmdBase ++{ ++ // Statics: ++ public: ++ // Required by the CMICmdFactory when registering *this command ++ static CMICmdBase *CreateSelf(void); ++ ++ // Methods: ++ public: ++ /* ctor */ CMICmdCmdGdbShow(void); ++ ++ // Overridden: ++ public: ++ // From CMICmdInvoker::ICmd ++ virtual bool Execute(void); ++ virtual bool Acknowledge(void); ++ virtual bool ParseArgs(void); ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmdCmdGdbShow(void); ++ ++ // Typedefs: ++ private: ++ typedef bool (CMICmdCmdGdbShow::*FnGdbOptionPtr)(const CMIUtilString::VecString_t &vrWords); ++ typedef std::map MapGdbOptionNameToFnGdbOptionPtr_t; ++ ++ // Methods: ++ private: ++ bool GetOptionFn(const CMIUtilString &vrGdbOptionName, FnGdbOptionPtr &vrwpFn) const; ++ bool OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords); ++ bool OptionFnFallback(const CMIUtilString::VecString_t &vrWords); ++ ++ // Attributes: ++ private: ++ const static MapGdbOptionNameToFnGdbOptionPtr_t ms_mapGdbOptionNameToFnGdbOptionPtr; ++ // ++ const CMIUtilString m_constStrArgNamedThreadGrp; ++ const CMIUtilString m_constStrArgNamedGdbOption; ++ bool m_bGdbOptionRecognised; // True = This command has a function with a name that matches the Print argument, false = not found ++ bool m_bGdbOptionFnSuccessful; // True = The print function completed its task ok, false = function failed for some reason ++ bool m_bGbbOptionFnHasError; // True = The option function has an error condition (not the command!), false = option function ok. ++ CMIUtilString m_strGdbOptionName; ++ CMIUtilString m_strGdbOptionFnError; ++ CMIUtilString m_strValue; ++}; +Index: tools/lldb-mi/MICmdCommands.cpp +=================================================================== +--- tools/lldb-mi/MICmdCommands.cpp (revision 226488) ++++ tools/lldb-mi/MICmdCommands.cpp (working copy) +@@ -37,6 +37,7 @@ + #include "MICmdCmdFile.h" + #include "MICmdCmdGdbInfo.h" + #include "MICmdCmdGdbSet.h" ++#include "MICmdCmdGdbShow.h" + #include "MICmdCmdGdbThread.h" + #include "MICmdCmdMiscellanous.h" + #include "MICmdCmdStack.h" +@@ -110,6 +111,7 @@ + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); ++ bOk &= Register(); + bOk &= Register(); + bOk &= Register(); + bOk &= Register(); Index: patches/lldbmi_hang_fix_select_insteadof_ioctl.patch =================================================================== --- /dev/null +++ patches/lldbmi_hang_fix_select_insteadof_ioctl.patch @@ -0,0 +1,143 @@ +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 224200) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -435,3 +435,15 @@ + return MIstatus::success; + } + ++//++ ------------------------------------------------------------------------------------ ++// Details: Do some actions before exiting. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++void ++CMICmnStreamStdin::OnExitHandler(void) ++{ ++ m_pStdinReadHandler->InterruptReadLine(); ++} +Index: tools/lldb-mi/MICmnStreamStdin.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.h (revision 224200) ++++ tools/lldb-mi/MICmnStreamStdin.h (working copy) +@@ -66,6 +66,7 @@ + public: + virtual bool InputAvailable(bool &vwbAvail) = 0; + virtual const MIchar *ReadLine(CMIUtilString &vwErrMsg) = 0; ++ virtual void InterruptReadLine(void){}; + + /* dtor */ virtual ~IOSStdinHandler(void){}; + }; +@@ -82,6 +83,7 @@ + void SetCtrlCHit(void); + bool SetVisitor(IStreamStdin &vrVisitor); + bool SetOSStdinHandler(IOSStdinHandler &vrHandler); ++ void OnExitHandler(void); + + // Overridden: + public: +Index: tools/lldb-mi/MICmnStreamStdinLinux.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinLinux.cpp (revision 224200) ++++ tools/lldb-mi/MICmnStreamStdinLinux.cpp (working copy) +@@ -20,13 +20,11 @@ + //-- + + // Third Party Headers: +-#if !defined(_MSC_VER) ++#if defined(__APPLE__) + #include +-#include +-#include +-#include +-#endif // !defined( _MSC_VER ) ++#endif // defined( __APPLE__ ) + #include // For std::strerror() ++#include // For STDIN_FILENO + + // In-house headers: + #include "MICmnStreamStdinLinux.h" +@@ -155,20 +153,26 @@ + bool + CMICmnStreamStdinLinux::InputAvailable(bool &vwbAvail) + { +-#if !defined(_WIN32) ++#if defined(__APPLE__) + // The code below is needed on OSX where lldb-mi hangs when doing -exec-run. + // The hang seems to come from calling fgets and fileno from different thread. + // Although this problem was not observed on Linux. + // A solution based on 'select' was also proposed but it seems to slow things down +- // a lot. +- int nBytesWaiting; +- if (::ioctl(STDIN_FILENO, FIONREAD, &nBytesWaiting) == -1) ++ // a lot on Linux platform. ++ // Therefore this code is used only on OSX. ++ fd_set setOfStdin; ++ FD_ZERO(&setOfStdin); ++ FD_SET(STDIN_FILENO, &setOfStdin); ++ ++ // Wait while input would be available ++ if (::select(STDIN_FILENO + 1, &setOfStdin, nullptr, nullptr, nullptr) == -1) + { + vwbAvail = false; +- return MIstatus::failure;; ++ return MIstatus::failure; + } +- vwbAvail = (nBytesWaiting > 0); +-#endif // !defined( _WIN32 ) ++ ++#endif // defined( __APPLE__ ) ++ vwbAvail = true; + return MIstatus::success; + } + +@@ -206,3 +210,15 @@ + return pText; + } + ++//++ ------------------------------------------------------------------------------------ ++// Details: Interrupt current and prevent new ReadLine operations. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++void ++CMICmnStreamStdinLinux::InterruptReadLine(void) ++{ ++ fclose(stdin); ++} +Index: tools/lldb-mi/MICmnStreamStdinLinux.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinLinux.h (revision 224200) ++++ tools/lldb-mi/MICmnStreamStdinLinux.h (working copy) +@@ -51,6 +51,7 @@ + // From CMICmnStreamStdin::IOSpecificReadStreamStdin + virtual bool InputAvailable(bool &vwbAvail); + virtual const MIchar *ReadLine(CMIUtilString &vwErrMsg); ++ virtual void InterruptReadLine(void); + + // Methods: + private: +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224200) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -1075,6 +1075,7 @@ + { + CMIUtilThreadLock lock(m_threadMutex); + m_bExitApp = true; ++ m_rStdin.OnExitHandler(); + return; + } + +@@ -1089,6 +1090,7 @@ + } + + m_bExitApp = true; ++ m_rStdin.OnExitHandler(); + } + + //++ ------------------------------------------------------------------------------------ Index: patches/lldbmi_hang_fix_via_select.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_hang_fix_via_select.v2.patch @@ -0,0 +1,361 @@ +Index: tools/lldb-mi/CMakeLists.txt +=================================================================== +--- tools/lldb-mi/CMakeLists.txt (revision 223116) ++++ tools/lldb-mi/CMakeLists.txt (working copy) +@@ -61,6 +61,7 @@ + MICmnStreamStderr.cpp + MICmnStreamStdin.cpp + MICmnStreamStdinLinux.cpp ++ MICmnStreamStdinOsx.cpp + MICmnStreamStdinWindows.cpp + MICmnStreamStdout.cpp + MICmnThreadMgrStd.cpp +@@ -142,6 +143,7 @@ + MICmnStreamStderr.cpp + MICmnStreamStdin.cpp + MICmnStreamStdinLinux.cpp ++ MICmnStreamStdinOsx.cpp + MICmnStreamStdinWindows.cpp + MICmnStreamStdout.cpp + MICmnThreadMgrStd.cpp +Index: tools/lldb-mi/MICmnStreamStdin.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdin.cpp (revision 223116) ++++ tools/lldb-mi/MICmnStreamStdin.cpp (working copy) +@@ -30,9 +30,11 @@ + #if defined(_MSC_VER) + #include "MIUtilSystemWindows.h" + #include "MICmnStreamStdinWindows.h" +-#else ++#elif defined(__APPLE__) ++#include "MICmnStreamStdinOsx.h" ++#else // linux, otherwise + #include "MICmnStreamStdinLinux.h" +-#endif // defined( _MSC_VER ) ++#endif // defined( _MSC_VER ) || defined( __APPLE__ ) + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmnStreamStdin constructor. +@@ -87,13 +89,16 @@ + MI::ModuleInit(IDS_MI_INIT_ERR_LOG, bOk, errMsg); + MI::ModuleInit(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); + MI::ModuleInit(IDS_MI_INIT_ERR_THREADMGR, bOk, errMsg); +-#ifdef _MSC_VER ++#if defined(_MSC_VER) + MI::ModuleInit(IDS_MI_INIT_ERR_OS_STDIN_HANDLER, bOk, errMsg); + bOk = bOk && SetOSStdinHandler(CMICmnStreamStdinWindows::Instance()); +-#else ++#elif defined(__APPLE__) ++ MI::ModuleInit(IDS_MI_INIT_ERR_OS_STDIN_HANDLER, bOk, errMsg); ++ bOk = bOk && SetOSStdinHandler(CMICmnStreamStdinOsx::Instance()); ++#else // linux, otherwise + MI::ModuleInit(IDS_MI_INIT_ERR_OS_STDIN_HANDLER, bOk, errMsg); + bOk = bOk && SetOSStdinHandler(CMICmnStreamStdinLinux::Instance()); +-#endif // ( _MSC_VER ) ++#endif // defined( _MSC_VER ) || defined( __APPLE__ ) + + // The OS specific stdin stream handler must be set before *this class initialises + if (bOk && m_pStdinReadHandler == nullptr) +@@ -149,11 +154,13 @@ + m_bKeyCtrlCHit = false; + + // Note shutdown order is important here +-#ifndef _MSC_VER ++#if defined(_MSC_VER) ++ MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); ++#elif defined(__APPLE__) ++ MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); ++#else // linux, otherwise + MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); +-#else +- MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER, bOk, errMsg); +-#endif // ( _MSC_VER ) ++#endif // defined( _MSC_VER ) || defined( __APPLE__ ) + MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_THREADMGR, bOk, errMsg); + MI::ModuleShutdown(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg); + MI::ModuleShutdown(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg); +Index: tools/lldb-mi/MICmnStreamStdinOsx.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinOsx.cpp (revision 0) ++++ tools/lldb-mi/MICmnStreamStdinOsx.cpp (working copy) +@@ -0,0 +1,204 @@ ++//===-- MICmnStreamStdinOsx.cpp --------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MIUtilStreamStdin.cpp ++// ++// Overview: CMICmnStreamStdinOsx implementation. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++// Third Party Headers: ++#if !defined(_MSC_VER) ++#include ++#endif // !defined( _MSC_VER ) ++#include // For std::strerror() ++#include // For STDIN_FILENO ++ ++// In-house headers: ++#include "MICmnStreamStdinOsx.h" ++#include "MICmnLog.h" ++#include "MICmnResources.h" ++#include "MIUtilSingletonHelper.h" ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmnStreamStdinOsx constructor. ++// Type: Method. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmnStreamStdinOsx::CMICmnStreamStdinOsx(void) ++ : m_constBufferSize(1024) ++ , m_pStdin(nullptr) ++ , m_pCmdBuffer(nullptr) ++{ ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: CMICmnStreamStdinOsx destructor. ++// Type: Overridable. ++// Args: None. ++// Return: None. ++// Throws: None. ++//-- ++CMICmnStreamStdinOsx::~CMICmnStreamStdinOsx(void) ++{ ++ Shutdown(); ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Initialize resources for *this Stdin stream. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdinOsx::Initialize(void) ++{ ++ if (m_bInitialized) ++ return MIstatus::success; ++ ++ bool bOk = MIstatus::success; ++ CMIUtilString errMsg; ++ ++ // Note initialisation order is important here as some resources depend on previous ++ MI::ModuleInit(IDS_MI_INIT_ERR_LOG, bOk, errMsg); ++ MI::ModuleInit(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); ++ ++ // Other resources required ++ if (bOk) ++ { ++ m_pCmdBuffer = new MIchar[m_constBufferSize]; ++ m_pStdin = stdin; ++ } ++ ++ // Clear error indicators for std input ++ ::clearerr(stdin); ++ ++ m_bInitialized = bOk; ++ ++ if (!bOk) ++ { ++ CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_OS_STDIN_HANDLER), errMsg.c_str())); ++ SetErrorDescription(strInitError); ++ return MIstatus::failure; ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Release resources for *this Stdin stream. ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdinOsx::Shutdown(void) ++{ ++ if (!m_bInitialized) ++ return MIstatus::success; ++ ++ m_bInitialized = false; ++ ++ ClrErrorDescription(); ++ ++ bool bOk = MIstatus::success; ++ CMIUtilString errMsg; ++ ++ // Tidy up ++ if (m_pCmdBuffer != nullptr) ++ { ++ delete[] m_pCmdBuffer; ++ m_pCmdBuffer = nullptr; ++ } ++ m_pStdin = nullptr; ++ ++ // Note shutdown order is important here ++ MI::ModuleShutdown(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg); ++ MI::ModuleShutdown(IDS_MI_INIT_ERR_LOG, bOk, errMsg); ++ ++ if (!bOk) ++ { ++ SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER), errMsg.c_str()); ++ } ++ ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Determine if stdin has any characters present in its buffer. ++// Type: Method. ++// Args: vwbAvail - (W) True = There is chars available, false = nothing there. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnStreamStdinOsx::InputAvailable(bool &vwbAvail) ++{ ++ fd_set setOfStdin; ++ FD_ZERO(&setOfStdin); ++ FD_SET(STDIN_FILENO, &setOfStdin); ++ ++ // Wait while input would be available ++ int nfds = select(STDIN_FILENO + 1, &setOfStdin, nullptr, nullptr, nullptr); ++ if (-1 == nfds) ++ { ++ vwbAvail = false; ++ return MIstatus::failure; ++ } ++ ++ vwbAvail = (1 == nfds); ++ return MIstatus::success; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r'). ++// Type: Method. ++// Args: vwErrMsg - (W) Empty string ok or error description. ++// Return: MIchar * - text buffer pointer or NULL on failure. ++// Throws: None. ++//-- ++const MIchar * ++CMICmnStreamStdinOsx::ReadLine(CMIUtilString &vwErrMsg) ++{ ++ vwErrMsg.clear(); ++ ++ // Read user input ++ const MIchar *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin); ++ if (pText == nullptr) ++ { ++ if (::ferror(m_pStdin) != 0) ++ vwErrMsg = ::strerror(errno); ++ return nullptr; ++ } ++ ++ // Strip off new line characters ++ for (MIchar *pI = m_pCmdBuffer; *pI != '\0'; pI++) ++ { ++ if ((*pI == '\n') || (*pI == '\r')) ++ { ++ *pI = '\0'; ++ break; ++ } ++ } ++ ++ return pText; ++} +Index: tools/lldb-mi/MICmnStreamStdinOsx.h +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinOsx.h (revision 0) ++++ tools/lldb-mi/MICmnStreamStdinOsx.h (working copy) +@@ -0,0 +1,71 @@ ++//===-- MICmnStreamStdinOsx.h --------------------------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++//++ ++// File: MIUtilStreamStdin.h ++// ++// Overview: CMICmnStreamStdinOsx interface. ++// ++// Environment: Compilers: Visual C++ 12. ++// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 ++// Libraries: See MIReadmetxt. ++// ++// Copyright: None. ++//-- ++ ++#pragma once ++ ++// In-house headers: ++#include "MICmnBase.h" ++#include "MICmnStreamStdin.h" ++#include "MIUtilSingletonBase.h" ++ ++//++ ============================================================================ ++// Details: MI common code class. Specific OS stdin handling implementation. ++// CMICmnStreamStdin instance is set with stdin handler before using the ++// the stream. An instance of this class must be set up and ready to give ++// to the CMICmnStreamStdin before it initialises other CMICmnStreamStdin ++// will give an error. ++// Gotchas: None. ++// Authors: Ilia Kirianovskii 02/12/2014. ++// Changes: None. ++//-- ++class CMICmnStreamStdinOsx : public CMICmnBase, public CMICmnStreamStdin::IOSStdinHandler, public MI::ISingleton ++{ ++ // Give singleton access to private constructors ++ friend MI::ISingleton; ++ ++ // Methods: ++ public: ++ bool Initialize(void); ++ bool Shutdown(void); ++ ++ // Overridden: ++ public: ++ // From CMICmnStreamStdin::IOSpecificReadStreamStdin ++ virtual bool InputAvailable(bool &vwbAvail); ++ virtual const MIchar *ReadLine(CMIUtilString &vwErrMsg); ++ ++ // Methods: ++ private: ++ /* ctor */ CMICmnStreamStdinOsx(void); ++ /* ctor */ CMICmnStreamStdinOsx(const CMICmnStreamStdin &); ++ void operator=(const CMICmnStreamStdin &); ++ ++ // Overridden: ++ private: ++ // From CMICmnBase ++ /* dtor */ virtual ~CMICmnStreamStdinOsx(void); ++ ++ // Attributes: ++ private: ++ const MIuint m_constBufferSize; ++ FILE *m_pStdin; ++ MIchar *m_pCmdBuffer; ++}; Index: patches/lldbmi_keep_icanon_mode.patch =================================================================== --- /dev/null +++ patches/lldbmi_keep_icanon_mode.patch @@ -0,0 +1,47 @@ +Index: tools/lldb-mi/MICmnStreamStdinLinux.cpp +=================================================================== +--- tools/lldb-mi/MICmnStreamStdinLinux.cpp (revision 223237) ++++ tools/lldb-mi/MICmnStreamStdinLinux.cpp (working copy) +@@ -91,6 +91,13 @@ + // Clear error indicators for std input + ::clearerr(stdin); + ++#if !defined(_WIN32) ++ // This code needed for correct work of ioctl(STDIN_FILENO, FIONREAD) ++ // in CMICmnStreamStdinLinux::InputAvailable(). ++ // Disable buffering for std input ++ ::setbuf(stdin, NULL); ++#endif // !defined( _WIN32 ) ++ + m_bInitialized = bOk; + + if (!bOk) +@@ -161,23 +168,14 @@ + // Although this problem was not observed on Linux. + // A solution based on 'select' was also proposed but it seems to slow things down + // a lot. +- static bool bInitialized = false; +- +- if (!bInitialized) ++ int nBytesWaiting; ++ if (::ioctl(STDIN_FILENO, FIONREAD, &nBytesWaiting) == -1) + { +- // Use termios to turn off line buffering +- ::termios term; +- ::tcgetattr(STDIN_FILENO, &term); +- term.c_lflag &= ~ICANON; +- ::tcsetattr(STDIN_FILENO, TCSANOW, &term); +- ::setbuf(stdin, NULL); +- bInitialized = true; ++ vwbAvail = false; ++ return MIstatus::failure;; + } +- +- int nBytesWaiting; +- ::ioctl(STDIN_FILENO, FIONREAD, &nBytesWaiting); + vwbAvail = (nBytesWaiting > 0); +-#endif ++#endif // !defined( _WIN32 ) + return MIstatus::success; + } + Index: patches/lldbmi_refactor_mi_tests.patch =================================================================== --- /dev/null +++ patches/lldbmi_refactor_mi_tests.patch @@ -0,0 +1,1233 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 227022) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -2,197 +2,95 @@ + Test that the lldb-mi driver understands an MI breakpoint command. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiBreakpointTestCase(TestBase): ++class MiBreakpointTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_pendbreakonsym(self): + """Test that 'lldb-mi --interpreter' works for pending symbol breakpoints.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- child.sendline("-break-insert -f a_MyFunction") +- child.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_pendbreakonsrc(self): + """Test that 'lldb-mi --interpreter' works for pending source breakpoints.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- # Find the line number to break inside main() and set +- # pending BP. +- self.line = line_number('main.c', '//BP_source') +- child.sendline("-break-insert -f main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"1\"") ++ # Find the line number to break inside main() and set ++ # pending BP. ++ line = line_number('main.c', '//BP_source') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_breakpoints(self): + """Test that 'lldb-mi --interpreter' works for breakpoints.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- child.sendline("-break-insert -f main") +- child.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol +- child.sendline("-break-insert a_MyFunction") +- child.expect("\^done,bkpt={number=\"2\"") ++ #break on symbol ++ self.runCmd("-break-insert a_MyFunction") ++ self.expect("\^done,bkpt={number=\"2\"") + +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source +- self.line = line_number('main.c', '//BP_source') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"3\"") ++ #break on source ++ line = line_number('main.c', '//BP_source') ++ self.runCmd("-break-insert main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"3\"") + +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ #run to exit ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- self.expect(from_child, exe=False, +- substrs = ["breakpoint-hit"]) +- +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 227022) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -2,131 +2,88 @@ + Test that the lldb-mi driver can evaluate expressions. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiEvaluateTestCase(TestBase): ++class MiEvaluateTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_eval(self): + """Test that 'lldb-mi --interpreter' works for evaluating.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- #run to main +- child.sendline("-break-insert -f main") +- child.expect("\^done,bkpt={number=\"1\"") ++ #run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to program return (marked BP_source) +- self.line = line_number('main.c', '//BP_source') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") ++ #run to program return (marked BP_source) ++ line = line_number('main.c', '//BP_source') ++ self.runCmd("-break-insert main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") + +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #print non-existant variable +- #child.sendline("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} +- #child.expect("error") +- #child.sendline("-data-evaluate-expression undef") #FIXME: gets value="undef" +- #child.expect("error") ++ #print non-existant variable ++ #self.runCmd("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} ++ #self.expect("error") ++ #self.runCmd("-data-evaluate-expression undef") #FIXME: gets value="undef" ++ #self.expect("error") + +- #print global "g_MyVar" +- child.sendline("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" +- child.expect("value=\"3\",type=\"int\"") +- #child.sendline("-var-evaluate-expression var1") #FIXME: gets var1 does not exist +- child.sendline("-var-show-attributes var1") +- child.expect("status=\"editable\"") +- child.sendline("-var-delete var1") +- child.expect("\^done") +- child.sendline("-var-create var1 --thread 1 --frame 0 * g_MyVar") +- child.expect("value=\"3\",type=\"int\"") ++ #print global "g_MyVar" ++ self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" ++ self.expect("value=\"3\",type=\"int\"") ++ #self.runCmd("-var-evaluate-expression var1") #FIXME: gets var1 does not exist ++ self.runCmd("-var-show-attributes var1") ++ self.expect("status=\"editable\"") ++ self.runCmd("-var-delete var1") ++ self.expect("\^done") ++ self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") ++ self.expect("value=\"3\",type=\"int\"") + +- #print static "s_MyVar" and modify +- child.sendline("-data-evaluate-expression s_MyVar") +- child.expect("value=\"30\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") +- child.expect("value=\"3\",type=\"int\"") +- child.sendline("-data-evaluate-expression \"s_MyVar=30\"") +- child.expect("value=\"30\"") ++ #print static "s_MyVar" and modify ++ self.runCmd("-data-evaluate-expression s_MyVar") ++ self.expect("value=\"30\"") ++ self.runCmd("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") ++ self.expect("value=\"3\",type=\"int\"") ++ self.runCmd("-data-evaluate-expression \"s_MyVar=30\"") ++ self.expect("value=\"30\"") + +- #print local "b" and modify +- child.sendline("-data-evaluate-expression b") +- child.expect("value=\"20\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"b=3\"") +- child.expect("value=\"3\",type=\"int\"") +- child.sendline("-data-evaluate-expression \"b=20\"") +- child.expect("value=\"20\"") ++ #print local "b" and modify ++ self.runCmd("-data-evaluate-expression b") ++ self.expect("value=\"20\"") ++ self.runCmd("-var-create var3 --thread 1 --frame 0 * \"b=3\"") ++ self.expect("value=\"3\",type=\"int\"") ++ self.runCmd("-data-evaluate-expression \"b=20\"") ++ self.expect("value=\"20\"") + +- #print "a + b" +- child.sendline("-data-evaluate-expression \"a + b\"") +- child.expect("value=\"30\"") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"a + b\"") +- child.expect("value=\"30\",type=\"int\"") ++ #print "a + b" ++ self.runCmd("-data-evaluate-expression \"a + b\"") ++ self.expect("value=\"30\"") ++ self.runCmd("-var-create var3 --thread 1 --frame 0 * \"a + b\"") ++ self.expect("value=\"30\",type=\"int\"") + +- #print "argv[0]" +- child.sendline("-data-evaluate-expression \"argv[0]\"") +- child.expect("value=\"0x") +- child.sendline("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") +- child.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") ++ #print "argv[0]" ++ self.runCmd("-data-evaluate-expression \"argv[0]\"") ++ self.expect("value=\"0x") ++ self.runCmd("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") ++ self.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") + +- #run to exit +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ #run to exit ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiInterrupt.py +=================================================================== +--- test/tools/lldb-mi/TestMiInterrupt.py (revision 227022) ++++ test/tools/lldb-mi/TestMiInterrupt.py (working copy) +@@ -2,96 +2,53 @@ + Test that the lldb-mi driver can interrupt and resume a looping app. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiInterruptTestCase(TestBase): ++class MiInterruptTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- ++ @lldbmi_test + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- @lldbmi_test + def test_lldbmi_interrupt(self): + """Test that 'lldb-mi --interpreter' interrupt and resume a looping app.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- #run to main +- child.sendline("-break-insert -f main") +- child.expect("\^done,bkpt={number=\"1\"") +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ #run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #set doloop=1 and run (to loop forever) +- child.sendline("-data-evaluate-expression \"doloop=1\"") +- child.expect("value=\"1\"") +- child.sendline("-exec-continue") +- child.expect("\^running") ++ #set doloop=1 and run (to loop forever) ++ self.runCmd("-data-evaluate-expression \"doloop=1\"") ++ self.expect("value=\"1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") + +- #issue interrupt, set BP in loop (marked BP_loop), and resume +- child.sendline("-exec-interrupt") +- child.expect("\*stopped,reason=\"signal-received\"") +- self.line = line_number('loop.c', '//BP_loop') +- child.sendline("-break-insert loop.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- #child.sendline("-exec-resume") #FIXME: command not recognized +- child.sendline("-exec-continue") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ #issue interrupt, set BP in loop (marked BP_loop), and resume ++ self.runCmd("-exec-interrupt") ++ self.expect("\*stopped,reason=\"signal-received\"") ++ line = line_number('loop.c', '//BP_loop') ++ self.runCmd("-break-insert loop.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") ++ #self.runCmd("-exec-resume") #FIXME: command not recognized ++ self.runCmd("-exec-continue") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #we should have hit BP +- #set loop=-1 so we'll exit the loop +- child.sendline("-data-evaluate-expression \"loop=-1\"") +- child.expect("value=\"-1\"") +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ #we should have hit BP ++ #set loop=-1 so we'll exit the loop ++ self.runCmd("-data-evaluate-expression \"loop=-1\"") ++ self.expect("value=\"-1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiLaunch.py +=================================================================== +--- test/tools/lldb-mi/TestMiLaunch.py (revision 227022) ++++ test/tools/lldb-mi/TestMiLaunch.py (working copy) +@@ -2,188 +2,71 @@ + Test various ways the lldb-mi driver can launch a program. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiLaunchTestCase(TestBase): ++class MiLaunchTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_exe(self): + """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols exe.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- #use no path +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ #use no path ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_abspathexe(self): + """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols fullpath/exe.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- #use full path +- exe = os.path.join(os.getcwd(), "a.out") +- child.sendline("-file-exec-and-symbols " + exe) +- child.expect("\^done") ++ #use full path ++ import os ++ exe = os.path.join(os.getcwd(), self.myexe) ++ self.runCmd("-file-exec-and-symbols %s" % exe) ++ self.expect("\^done") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_relpathexe(self): + """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols relpath/exe.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- #use relative path +- exe = "../../" + self.mydir + "/" + self.myexe +- child.sendline("-file-exec-and-symbols " + exe) +- child.expect("\^done") ++ #use relative path ++ exe = "../../" + self.mydir + "/" + self.myexe ++ self.runCmd("-file-exec-and-symbols %s" % exe) ++ self.expect("\^done") + +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_badpathexe(self): + """Test that 'lldb-mi --interpreter' works for -file-exec-and-symbols badpath/exe.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- #use non-existant path +- exe = "badpath/" + self.myexe +- child.sendline("-file-exec-and-symbols " + exe) +- child.expect("\^error") ++ #use non-existant path ++ exe = "badpath/" + self.myexe ++ self.runCmd("-file-exec-and-symbols %s" % exe) ++ self.expect("\^error") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 227022) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -2,86 +2,44 @@ + Test that the lldb-mi driver can pass arguments to the app. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiProgramArgsTestCase(TestBase): ++class MiProgramArgsTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- ++ @lldbmi_test + @unittest2.skip("lldb-mi can't pass params to app.") +- @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_paramargs(self): + """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("-file-exec-and-symbols " + self.myexe) +- child.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- child.sendline("settings set target.run-args l") #FIXME: args not passed +- #child.sendline("-exec-arguments l") #FIXME: not recognized and hung lldb-mi ++ self.runCmd("settings set target.run-args l") #FIXME: args not passed ++ #self.runCmd("-exec-arguments l") #FIXME: not recognized and hung lldb-mi + +- #run to main +- child.sendline("-break-insert -f main") +- child.expect("\^done,bkpt={number=\"1\"") +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ #run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #check argc to see if arg passed +- child.sendline("-data-evaluate-expression argc") +- child.expect("value=\"2\"") ++ #check argc to see if arg passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("value=\"2\"") + +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- self.line = line_number('main.c', '//BP_argtest') +- child.sendline("-break-insert main.c:%d" % self.line) +- child.expect("\^done,bkpt={number=\"2\"") +- child.sendline("-exec-continue") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) ++ line = line_number('main.c', '//BP_argtest') ++ self.runCmd("-break-insert main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 227022) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -2,123 +2,60 @@ + Test that the lldb-mi driver works with -stack-xxx commands + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiStackTestCase(TestBase): ++class MiStackTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_stackargs(self): + """Test that 'lldb-mi --interpreter' can shows arguments.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- # Load executable +- child.sendline("-file-exec-and-symbols %s" % (self.myexe)) +- child.expect("\^done") ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") + +- # Run to main +- child.sendline("-break-insert -f main") +- child.expect("\^done,bkpt={number=\"1\"") +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- # Test arguments +- child.sendline("-stack-list-arguments 0") +- child.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ # Test arguments ++ #self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work ++ #self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") ++ self.runCmd("-stack-list-arguments 1") ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_locals(self): + """Test that 'lldb-mi --interpreter' can shows local variables.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- # Load executable +- child.sendline("-file-exec-and-symbols %s" % (self.myexe)) +- child.expect("\^done") ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % (self.myexe)) ++ self.expect("\^done") + +- # Run to main +- self.line = line_number('main.c', '//BP_localstest') +- child.sendline("-break-insert --file main.c:%d" % (self.line)) +- child.expect("\^done,bkpt={number=\"1\"") +- child.sendline("-exec-run") +- child.expect("\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ # Run to main ++ line = line_number('main.c', '//BP_localstest') ++ self.runCmd("-break-insert --file main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- # Test locals +- child.sendline("-stack-list-locals 0") +- child.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ # Test locals ++ #self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work ++ #self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") ++ self.runCmd("-stack-list-locals 1") ++ self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 227022) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -2,74 +2,34 @@ + Test that the lldb-mi driver understands MI command syntax. + """ + +-import os ++import lldbmi_testcase ++from lldbtest import * + import unittest2 +-import lldb +-from lldbtest import * + +-class MiSyntaxTestCase(TestBase): ++class MiSyntaxTestCase(lldbmi_testcase.MiTestCaseBase): + +- mydir = TestBase.compute_mydir(__file__) +- myexe = "a.out" +- +- @classmethod +- def classCleanup(cls): +- """Cleanup the test byproducts.""" +- try: +- os.remove("child_send.txt") +- os.remove("child_read.txt") +- os.remove(cls.myexe) +- except: +- pass +- + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_tokens(self): + """Test that 'lldb-mi --interpreter' echos command tokens.""" +- import pexpect +- self.buildDefault() + +- # So that the child gets torn down after the test. +- self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) +- child = self.child +- child.setecho(True) +- # Turn on logging for input/output to/from the child. +- with open('child_send.txt', 'w') as f_send: +- with open('child_read.txt', 'w') as f_read: +- child.logfile_send = f_send +- child.logfile_read = f_read ++ self.spawnLldbMi(args = None) + +- child.sendline("000-file-exec-and-symbols " + self.myexe) +- child.expect("000\^done") ++ # Load executable ++ self.runCmd("000-file-exec-and-symbols %s" % self.myexe) ++ self.expect("000\^done") + +- child.sendline("100000001-break-insert -f a_MyFunction") +- child.expect("100000001\^done,bkpt={number=\"1\"") ++ # Run to main ++ self.runCmd("100000001-break-insert -f a_MyFunction") ++ self.expect("100000001\^done,bkpt={number=\"1\"") ++ self.runCmd("2-exec-run") ++ self.expect("2\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- child.sendline("2-exec-run") +- child.expect("2\^running") +- child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ # Exit ++ self.runCmd("0000000000000000000003-exec-continue") ++ self.expect("0000000000000000000003\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") + +- child.sendline("0000000000000000000003-exec-continue") +- child.expect("0000000000000000000003\^running") +- child.expect("\*stopped,reason=\"exited-normally\"") +- +- # Now that the necessary logging is done, restore logfile to None to +- # stop further logging. +- child.logfile_send = None +- child.logfile_read = None +- +- with open('child_send.txt', 'r') as fs: +- if self.TraceOn(): +- print "\n\nContents of child_send.txt:" +- print fs.read() +- with open('child_read.txt', 'r') as fr: +- from_child = fr.read() +- if self.TraceOn(): +- print "\n\nContents of child_read.txt:" +- print from_child +- + if __name__ == '__main__': +- import atexit +- lldb.SBDebugger.Initialize() +- atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() +Index: test/tools/lldb-mi/lldbmi_testcase.py +=================================================================== +--- test/tools/lldb-mi/lldbmi_testcase.py (revision 0) ++++ test/tools/lldb-mi/lldbmi_testcase.py (working copy) +@@ -0,0 +1,41 @@ ++""" ++Base class for lldb-mi test cases. ++""" ++ ++from lldbtest import * ++import pexpect ++import unittest2 ++ ++class MiTestCaseBase(Base): ++ ++ mydir = Base.compute_mydir(__file__) ++ myexe = "a.out" ++ mylog = "child.log" ++ ++ @classmethod ++ def classCleanup(cls): ++ TestBase.RemoveTempFile(cls.myexe) ++ TestBase.RemoveTempFile(cls.mylog) ++ ++ def setUp(self): ++ Base.setUp(self) ++ self.buildDefault() ++ self.child_prompt = "(gdb)" ++ ++ def tearDown(self): ++ if self.TraceOn(): ++ print "\n\nContents of %s:" % self.mylog ++ print open(self.mylog, "r").read() ++ Base.tearDown(self) ++ ++ def spawnLldbMi(self, args=None): ++ self.child = pexpect.spawn("%s --interpreter %s" % ( ++ self.lldbMiExec, args if args else "")) ++ self.child.setecho(True) ++ self.child.logfile_read = open(self.mylog, "w") ++ ++ def runCmd(self, cmd): ++ self.child.sendline(cmd) ++ ++ def expect(self, pattern, *args, **kwargs): ++ self.child.expect(pattern, *args, **kwargs) Index: patches/lldbmi_s_support.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_s_support.v2.patch @@ -0,0 +1,442 @@ +Index: test/tools/lldb-mi/TestMiStartupOptions.py +=================================================================== +--- test/tools/lldb-mi/TestMiStartupOptions.py (revision 0) ++++ test/tools/lldb-mi/TestMiStartupOptions.py (working copy) +@@ -0,0 +1,157 @@ ++""" ++Test that the lldb-mi driver handle startup options correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiStartupOptionsTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_sourceoption(self): ++ """Test that 'lldb-mi --interpreter' can execute a prepared file which passed via --source option.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt (seriously?!). ++ prompt = "(gdb)" ++ ++ # Prepared source file ++ sourcefile = "main.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # after '-file-exec-and-symbols a.out' ++ child.expect_exact("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # after '-break-insert -f main' ++ child.expect_exact("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ ++ # after '-exec-run' ++ child.expect_exact("-exec-run") ++ child.sendline("") #FIXME: hangs here; extra return is needed ++ child.expect("\^running") ++ ++ # after '-exec-next --thread 1 --frame 0' ++ child.expect_exact("-exec-next --thread 1 --frame 0") ++ child.expect("\^running") ++ ++ # after '-break-insert -f main.c:22' ++ child.expect_exact("-break-insert -f main.c:22") ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # after '-exec-continue' ++ child.expect_exact("-exec-continue") ++ child.expect("\^running") ++ ++ # after '-data-evaluate-expression a' ++ child.expect_exact("-data-evaluate-expression a") ++ child.expect("\^done,value=\"10\"") ++ ++ # after '-gdb-exit' ++ child.expect_exact("-gdb-exit") ++ child.expect("\^exit") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ ++ @unittest2.skip("exec-run hangs and requires extra return") ++ @lldbmi_test ++ def test_lldbmi_quietlyoption(self): ++ """Test that 'lldb-mi --interpreter' can execute a prepared file quietly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt (seriously?!). ++ prompt = "(gdb)" ++ ++ # Prepared source file ++ sourcefile = "main.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source-quietly --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # setup list of unexpected patterns ++ unexpected = [ ++ "-file-exec-and-symbols %s" % (self.myexe), ++ "-break-insert -f main", ++ "-exec-run", ++ "-exec-next --thread 1 --frame 0", ++ "-break-insert -f main.c:22", ++ "-exec-continue", ++ "-data-evaluate-expression a", ++ "-gdb-exit", ++ ] ++ # try to find any unxpected patterns ++ it = child.expect(unexpected + [ pexpect.EOF ]) ++ # expect() for unexpected should returns pexpect.EOF ++ if it != len(unexpected): ++ # generate error if it's not pexpect.EOF ++ child.expect_exact("$UNEXPECTED FOUND: %s.^" % (unexpected[it])) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/main.micmds +=================================================================== +--- test/tools/lldb-mi/main.micmds (revision 0) ++++ test/tools/lldb-mi/main.micmds (working copy) +@@ -0,0 +1,8 @@ ++-file-exec-and-symbols a.out ++-break-insert -f main ++-exec-run ++-exec-next --thread 1 --frame 0 ++-break-insert -f main.c:22 ++-exec-continue ++-data-evaluate-expression a ++-gdb-exit +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 222919) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Stop(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 222919) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -82,6 +82,11 @@ + {IDE_MI_APP_ARG_EXECUTEABLE, "--executable\n\tUse the MI Driver in MI mode for the debugging the specified\n\texecutable. Any LLDB " + "command line options are ignored even\n\tif the MI Driver falls through to the LLDB driver. " + "(Depends\n\ton the build configuration see MICmnConfig.h)\n\tNormally specified from the command line."}, ++ {IDE_MI_APP_ARG_SOURCE, "-s \n--source \n\t" ++ "Tells the debugger to read in and execute the lldb commands in the\n\t" ++ "given file, after any file provided on the command line has been\n\tloaded."}, ++ {IDE_MI_APP_ARG_SOURCE_QUIETLY, "-Q\n--source-quietly\n\t" ++ "Tells the debugger suppress output from commands provided in the\n\t-s command."}, + {IDE_MI_APP_ARG_NO_APP_LOG, "--noLog\n\tUse this argument to tell the MI Driver not to update it's log\n\tfile '%s'."}, + {IDE_MI_APP_ARG_EXAMPLE, "Example MI command:\n\t3-info-gdb-mi-command gdb-set\n\t3^done,command={exists=\"true\"}"}, + {IDE_MI_APP_ARG_EXECUTABLE, "executable (NOT IMPLEMENTED)\n\tThe file path to the executable i.e. '\"C:\\My Dev\\foo.exe\"'."}, +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 222919) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -89,6 +89,8 @@ + IDE_MI_APP_ARG_VERSION_LONG, + IDE_MI_APP_ARG_INTERPRETER, + IDE_MI_APP_ARG_EXECUTEABLE, ++ IDE_MI_APP_ARG_SOURCE, ++ IDE_MI_APP_ARG_SOURCE_QUIETLY, + IDE_MI_APP_ARG_NO_APP_LOG, + IDE_MI_APP_ARG_EXAMPLE, + IDE_MI_APP_ARG_EXECUTABLE, +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 222919) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -22,6 +22,7 @@ + // Third party headers: + #include // va_list, va_start, var_end + #include ++#include + #include + + // In-house headers: +@@ -41,6 +42,7 @@ + #include "MICmdArgValFile.h" + #include "MICmdArgValString.h" + #include "MICmnConfig.h" ++#include "MICmnLLDBDebugSessionInfo.h" + + // Instantiations: + #if _DEBUG +@@ -68,6 +70,8 @@ + , m_eCurrentDriverState(eDriverState_NotRunning) + , m_bHaveExecutableFileNamePathOnCmdLine(false) + , m_bDriverDebuggingArgExecutable(false) ++ , m_bHaveSourceQuietlyOnCmdLine(false) ++ , m_bHaveCommandFileNamePathOnCmdLine(false) + { + } + +@@ -410,16 +414,18 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Check the arguments that were passed to this program to make sure they are +-// valid and to get their argument values (if any). The following are options +-// that are only handled by *this driver: ++// valid and to get their argument values (if any). The following are the only ++// options handled by this driver: + // --executable ++// --source or -s ++// --source-quietly or -Q + // The application's options --interpreter and --executable in code act very similar. + // The --executable is necessary to differentiate whither the MI Driver is being +-// using by a client i.e. Eclipse or from the command line. Eclipse issues the option ++// using by a client (e.g. Eclipse) or from the command line. Eclipse issues the option + // --interpreter and also passes additional arguments which can be interpreted as an +-// executable if called from the command line. Using --executable tells the MI +-// Driver is being called the command line and that the executable argument is indeed +-// a specified executable an so actions commands to set up the executable for a ++// executable if called from the command line. Using --executable tells the MI Driver ++// it is being called from the command line and that the executable argument is indeed ++// a specified executable and should so actions commands to set up the executable for a + // debug session. Using --interpreter on the commnd line does not action additional + // commands to initialise a debug session and so be able to launch the process. + // Type: Overridden. +@@ -451,20 +457,45 @@ + + if (bHaveArgs) + { +- // Search right to left to look for the executable ++ // Search right to left to look for filenames + for (MIint i = argc - 1; i > 0; i--) + { + const CMIUtilString strArg(argv[i]); + const CMICmdArgValFile argFile; ++ ++ // Check for a filename + if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg)) + { ++ // Is this the command file for the '-s' or '--source' options? ++ const CMIUtilString strPrevArg(argv[i - 1]); ++ if (strPrevArg.compare("-s") == 0 || strPrevArg.compare("--source") == 0) ++ { ++ m_strCmdLineArgCommandFileNamePath = argFile.GetFileNamePath(strArg); ++ m_bHaveCommandFileNamePathOnCmdLine = true; ++ i--; // skip '-s' on the next loop ++ continue; ++ } ++ // Else, must be the executable + bHaveExecutableFileNamePath = true; + m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath(strArg); + m_bHaveExecutableFileNamePathOnCmdLine = true; + } +- // This argument is also check for in CMIDriverMgr::ParseArgs() +- if (0 == strArg.compare("--executable")) // Used to specify that there is executable argument also on the command line +- { // See fn description. ++ // Report error if no command file was specified for the '-s' or '--source' options ++ else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) ++ { ++ vwbExiting = true; ++ const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str()); ++ errStatus.SetErrorString(errMsg.c_str()); ++ break; ++ } ++ // Execute quietly? ++ else if (strArg.compare("-Q") == 0 || strArg.compare("--source-quietly") == 0) ++ { ++ m_bHaveSourceQuietlyOnCmdLine = true; ++ } ++ // This argument is also checked for in CMIDriverMgr::ParseArgs() ++ else if (strArg.compare("--executable") == 0) // Used to specify that there is executable argument also on the command line ++ { // See fn description. + bHaveExecutableLongOption = true; + } + } +@@ -623,6 +654,14 @@ + } + #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION + ++ bool bOk = MIstatus::success; ++ // Handle source file ++ if (m_bHaveCommandFileNamePathOnCmdLine) ++ { ++ const bool bAsyncMode = false; ++ bOk = ExecuteCommandFile(bAsyncMode); ++ } ++ + // While the app is active + while (!m_bExitApp) + { +@@ -643,7 +682,7 @@ + // Ensure that a new line is sent as the last act of the dying driver + m_rStdOut.WriteMIResponse("\n", false); + +- return MIstatus::success; ++ return bOk; + } + + //++ ------------------------------------------------------------------------------------ +@@ -1325,3 +1364,55 @@ + { + return m_bDriverDebuggingArgExecutable; + } ++ ++// Helper function for CMIDriver::DoMainLoop. ++// Execute commands from source file in specific mode, and set exit-flag if needed ++//++ ------------------------------------------------------------------------------------ ++// Details: Execute commands from prepared source file ++// Type: Method. ++// Args: vbAsyncMode - (R) True = execute commands in asynchronous mode, false = otherwise. ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) ++{ ++ std::ifstream startScript(m_strCmdLineArgCommandFileNamePath.c_str()); ++ if (!startScript.is_open()) ++ { ++ m_bExitApp = true; ++ const CMIUtilString errMsg( ++ CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), m_strCmdLineArgCommandFileNamePath.c_str())); ++ SetErrorDescription(errMsg.c_str()); ++ return MIstatus::failure; ++ } ++ ++ // Switch lldb to synchronous mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncSetting = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ rSessionInfo.m_rLldbDebugger.SetAsync(vbAsyncMode); ++ ++ // Execute command from file ++ bool bOk = MIstatus::success; ++ CMIUtilString executedCommand; ++ while (std::getline(startScript, executedCommand)) ++ { ++ if (!m_bHaveSourceQuietlyOnCmdLine) ++ { ++ std::cout << executedCommand << std::endl; ++ } ++ bOk = InterpretCommand(executedCommand); ++ if (!bOk) ++ { ++ m_bExitApp = true; ++ bOk = MIstatus::failure; ++ break; ++ } ++ } ++ ++ // Switch lldb back to initial mode ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncSetting); ++ ++ return bOk; ++} +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 222919) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -154,6 +154,7 @@ + bool InitClientIDEEclipse(void) const; + bool QueueMICommand(const CMIUtilString &vMICmd); + bool LocalDebugSessionStartupInjectCommands(void); ++ bool ExecuteCommandFile(const bool vbAsyncMode); + + // Overridden: + private: +@@ -175,8 +176,12 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) ++ bool m_bHaveSourceQuietlyOnCmdLine; // True = the MI Driver (MI mode) executes initial commands from source file quietly, ++ // false = otherwise ++ bool m_bHaveCommandFileNamePathOnCmdLine; // True = file with initial commands given as one of the parameters to the MI Driver, false = not found ++ CMIUtilString m_strCmdLineArgCommandFileNamePath; + }; +Index: tools/lldb-mi/MIDriverMgr.cpp +=================================================================== +--- tools/lldb-mi/MIDriverMgr.cpp (revision 222919) ++++ tools/lldb-mi/MIDriverMgr.cpp (working copy) +@@ -686,6 +686,8 @@ + MIRSRC(IDE_MI_APP_ARG_VERSION), + MIRSRC(IDE_MI_APP_ARG_VERSION_LONG), + MIRSRC(IDE_MI_APP_ARG_INTERPRETER), ++ MIRSRC(IDE_MI_APP_ARG_SOURCE), ++ MIRSRC(IDE_MI_APP_ARG_SOURCE_QUIETLY), + MIRSRC(IDE_MI_APP_ARG_EXECUTEABLE), + CMIUtilString::Format(MIRSRC(IDE_MI_APP_ARG_NO_APP_LOG), CMICmnLogMediumFile::Instance().GetFileName().c_str()), + MIRSRC(IDE_MI_APP_ARG_EXECUTABLE), Index: patches/lldbmi_s_support.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_s_support.v3.patch @@ -0,0 +1,443 @@ +Index: test/tools/lldb-mi/TestMiStartupOptions.py +=================================================================== +--- test/tools/lldb-mi/TestMiStartupOptions.py (revision 0) ++++ test/tools/lldb-mi/TestMiStartupOptions.py (working copy) +@@ -0,0 +1,155 @@ ++""" ++Test that the lldb-mi driver handle startup options correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiStartupOptionsTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_sourceoption(self): ++ """Test that 'lldb-mi --interpreter' can execute a prepared file which passed via --source option.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt (seriously?!). ++ prompt = "(gdb)" ++ ++ # Prepared source file ++ sourcefile = "main.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # after '-file-exec-and-symbols a.out' ++ child.expect_exact("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # after '-break-insert -f main' ++ child.expect_exact("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ ++ # after '-exec-run' ++ child.expect_exact("-exec-run") ++ child.expect("\^running") ++ ++ # after '-exec-next --thread 1 --frame 0' ++ child.expect_exact("-exec-next --thread 1 --frame 0") ++ child.expect("\^running") ++ ++ # after '-break-insert -f main.c:22' ++ child.expect_exact("-break-insert -f main.c:22") ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # after '-exec-continue' ++ child.expect_exact("-exec-continue") ++ child.expect("\^running") ++ ++ # after '-data-evaluate-expression a' ++ child.expect_exact("-data-evaluate-expression a") ++ child.expect("\^done,value=\"10\"") ++ ++ # after '-gdb-exit' ++ child.expect_exact("-gdb-exit") ++ child.expect("\^exit") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ ++ @lldbmi_test ++ def test_lldbmi_quietlyoption(self): ++ """Test that 'lldb-mi --interpreter' can execute a prepared file quietly.""" ++ import pexpect ++ self.buildDefault() ++ ++ # The default lldb-mi prompt (seriously?!). ++ prompt = "(gdb)" ++ ++ # Prepared source file ++ sourcefile = "main.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source-quietly --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # setup list of unexpected patterns ++ unexpected = [ ++ "-file-exec-and-symbols %s" % (self.myexe), ++ "-break-insert -f main", ++ "-exec-run", ++ "-exec-next --thread 1 --frame 0", ++ "-break-insert -f main.c:22", ++ "-exec-continue", ++ "-data-evaluate-expression a", ++ "-gdb-exit", ++ ] ++ # try to find any unxpected patterns ++ it = child.expect(unexpected + [ pexpect.EOF ]) ++ # expect() for unexpected should returns pexpect.EOF ++ if it != len(unexpected): ++ # generate error if it's not pexpect.EOF ++ child.expect_exact("$UNEXPECTED FOUND: %s.^" % (unexpected[it])) ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/main.micmds +=================================================================== +--- test/tools/lldb-mi/main.micmds (revision 0) ++++ test/tools/lldb-mi/main.micmds (working copy) +@@ -0,0 +1,8 @@ ++-file-exec-and-symbols a.out ++-break-insert -f main ++-exec-run ++-exec-next --thread 1 --frame 0 ++-break-insert -f main.c:22 ++-exec-continue ++-data-evaluate-expression a ++-gdb-exit +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 224200) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Stop(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 224200) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -82,6 +82,11 @@ + {IDE_MI_APP_ARG_EXECUTEABLE, "--executable\n\tUse the MI Driver in MI mode for the debugging the specified\n\texecutable. Any LLDB " + "command line options are ignored even\n\tif the MI Driver falls through to the LLDB driver. " + "(Depends\n\ton the build configuration see MICmnConfig.h)\n\tNormally specified from the command line."}, ++ {IDE_MI_APP_ARG_SOURCE, "-s \n--source \n\t" ++ "Tells the debugger to read in and execute the lldb commands in the\n\t" ++ "given file, after any file provided on the command line has been\n\tloaded."}, ++ {IDE_MI_APP_ARG_SOURCE_QUIETLY, "-Q\n--source-quietly\n\t" ++ "Tells the debugger suppress output from commands provided in the\n\t-s command."}, + {IDE_MI_APP_ARG_NO_APP_LOG, "--noLog\n\tUse this argument to tell the MI Driver not to update it's log\n\tfile '%s'."}, + {IDE_MI_APP_ARG_EXAMPLE, "Example MI command:\n\t3-info-gdb-mi-command gdb-set\n\t3^done,command={exists=\"true\"}"}, + {IDE_MI_APP_ARG_EXECUTABLE, "executable (NOT IMPLEMENTED)\n\tThe file path to the executable i.e. '\"C:\\My Dev\\foo.exe\"'."}, +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 224200) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -89,6 +89,8 @@ + IDE_MI_APP_ARG_VERSION_LONG, + IDE_MI_APP_ARG_INTERPRETER, + IDE_MI_APP_ARG_EXECUTEABLE, ++ IDE_MI_APP_ARG_SOURCE, ++ IDE_MI_APP_ARG_SOURCE_QUIETLY, + IDE_MI_APP_ARG_NO_APP_LOG, + IDE_MI_APP_ARG_EXAMPLE, + IDE_MI_APP_ARG_EXECUTABLE, +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 224200) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -22,6 +22,7 @@ + // Third party headers: + #include // va_list, va_start, var_end + #include ++#include + #include + + // In-house headers: +@@ -41,6 +42,7 @@ + #include "MICmdArgValFile.h" + #include "MICmdArgValString.h" + #include "MICmnConfig.h" ++#include "MICmnLLDBDebugSessionInfo.h" + + // Instantiations: + #if _DEBUG +@@ -68,6 +70,8 @@ + , m_eCurrentDriverState(eDriverState_NotRunning) + , m_bHaveExecutableFileNamePathOnCmdLine(false) + , m_bDriverDebuggingArgExecutable(false) ++ , m_bHaveSourceQuietlyOnCmdLine(false) ++ , m_bHaveCommandFileNamePathOnCmdLine(false) + { + } + +@@ -410,16 +414,18 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Check the arguments that were passed to this program to make sure they are +-// valid and to get their argument values (if any). The following are options +-// that are only handled by *this driver: ++// valid and to get their argument values (if any). The following are the only ++// options handled by this driver: + // --executable ++// --source or -s ++// --source-quietly or -Q + // The application's options --interpreter and --executable in code act very similar. + // The --executable is necessary to differentiate whither the MI Driver is being +-// using by a client i.e. Eclipse or from the command line. Eclipse issues the option ++// using by a client (e.g. Eclipse) or from the command line. Eclipse issues the option + // --interpreter and also passes additional arguments which can be interpreted as an +-// executable if called from the command line. Using --executable tells the MI +-// Driver is being called the command line and that the executable argument is indeed +-// a specified executable an so actions commands to set up the executable for a ++// executable if called from the command line. Using --executable tells the MI Driver ++// it is being called from the command line and that the executable argument is indeed ++// a specified executable and should so actions commands to set up the executable for a + // debug session. Using --interpreter on the commnd line does not action additional + // commands to initialise a debug session and so be able to launch the process. + // Type: Overridden. +@@ -451,20 +457,45 @@ + + if (bHaveArgs) + { +- // Search right to left to look for the executable ++ // Search right to left to look for filenames + for (MIint i = argc - 1; i > 0; i--) + { + const CMIUtilString strArg(argv[i]); + const CMICmdArgValFile argFile; ++ ++ // Check for a filename + if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg)) + { ++ // Is this the command file for the '-s' or '--source' options? ++ const CMIUtilString strPrevArg(argv[i - 1]); ++ if (strPrevArg.compare("-s") == 0 || strPrevArg.compare("--source") == 0) ++ { ++ m_strCmdLineArgCommandFileNamePath = argFile.GetFileNamePath(strArg); ++ m_bHaveCommandFileNamePathOnCmdLine = true; ++ i--; // skip '-s' on the next loop ++ continue; ++ } ++ // Else, must be the executable + bHaveExecutableFileNamePath = true; + m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath(strArg); + m_bHaveExecutableFileNamePathOnCmdLine = true; + } +- // This argument is also check for in CMIDriverMgr::ParseArgs() +- if (0 == strArg.compare("--executable")) // Used to specify that there is executable argument also on the command line +- { // See fn description. ++ // Report error if no command file was specified for the '-s' or '--source' options ++ else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) ++ { ++ vwbExiting = true; ++ const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str()); ++ errStatus.SetErrorString(errMsg.c_str()); ++ break; ++ } ++ // Execute quietly? ++ else if (strArg.compare("-Q") == 0 || strArg.compare("--source-quietly") == 0) ++ { ++ m_bHaveSourceQuietlyOnCmdLine = true; ++ } ++ // This argument is also checked for in CMIDriverMgr::ParseArgs() ++ else if (strArg.compare("--executable") == 0) // Used to specify that there is executable argument also on the command line ++ { // See fn description. + bHaveExecutableLongOption = true; + } + } +@@ -623,6 +654,14 @@ + } + #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION + ++ bool bOk = MIstatus::success; ++ // Handle source file ++ if (m_bHaveCommandFileNamePathOnCmdLine) ++ { ++ const bool bAsyncMode = false; ++ bOk = ExecuteCommandFile(bAsyncMode); ++ } ++ + // While the app is active + while (!m_bExitApp) + { +@@ -643,7 +682,7 @@ + // Ensure that a new line is sent as the last act of the dying driver + m_rStdOut.WriteMIResponse("\n", false); + +- return MIstatus::success; ++ return bOk; + } + + //++ ------------------------------------------------------------------------------------ +@@ -1325,3 +1364,58 @@ + { + return m_bDriverDebuggingArgExecutable; + } ++ ++// Helper function for CMIDriver::DoMainLoop. ++// Execute commands from source file in specific mode, and set exit-flag if needed ++//++ ------------------------------------------------------------------------------------ ++// Details: Execute commands from prepared source file ++// Type: Method. ++// Args: vbAsyncMode - (R) True = execute commands in asynchronous mode, false = otherwise. ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) ++{ ++ std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str()); ++ if (!ifsStartScript.is_open()) ++ { ++ m_bExitApp = true; ++ const CMIUtilString errMsg( ++ CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), m_strCmdLineArgCommandFileNamePath.c_str())); ++ SetErrorDescription(errMsg.c_str()); ++ return MIstatus::failure; ++ } ++ ++ // Switch lldb to synchronous mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncSetting = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ rSessionInfo.m_rLldbDebugger.SetAsync(vbAsyncMode); ++ ++ // Execute commands from file ++ bool bOk = MIstatus::success; ++ CMIUtilString strCommand; ++ while (std::getline(ifsStartScript, strCommand)) ++ { ++ // Print command ++ if (!m_bHaveSourceQuietlyOnCmdLine) ++ std::cout << strCommand << std::endl; ++ ++ // Execute if no error ++ if (bOk) ++ bOk = InterpretCommand(strCommand); ++ ++ // Break if there is ++ if (!bOk) ++ { ++ m_bExitApp = true; ++ break; ++ } ++ } ++ ++ // Switch lldb back to initial mode ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncSetting); ++ ++ return bOk; ++} +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 224200) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -154,6 +154,7 @@ + bool InitClientIDEEclipse(void) const; + bool QueueMICommand(const CMIUtilString &vMICmd); + bool LocalDebugSessionStartupInjectCommands(void); ++ bool ExecuteCommandFile(const bool vbAsyncMode); + + // Overridden: + private: +@@ -175,8 +176,12 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) ++ bool m_bHaveSourceQuietlyOnCmdLine; // True = the MI Driver (MI mode) executes initial commands from source file quietly, ++ // false = otherwise ++ bool m_bHaveCommandFileNamePathOnCmdLine; // True = file with initial commands given as one of the parameters to the MI Driver, false = not found ++ CMIUtilString m_strCmdLineArgCommandFileNamePath; + }; +Index: tools/lldb-mi/MIDriverMgr.cpp +=================================================================== +--- tools/lldb-mi/MIDriverMgr.cpp (revision 224200) ++++ tools/lldb-mi/MIDriverMgr.cpp (working copy) +@@ -686,6 +686,8 @@ + MIRSRC(IDE_MI_APP_ARG_VERSION), + MIRSRC(IDE_MI_APP_ARG_VERSION_LONG), + MIRSRC(IDE_MI_APP_ARG_INTERPRETER), ++ MIRSRC(IDE_MI_APP_ARG_SOURCE), ++ MIRSRC(IDE_MI_APP_ARG_SOURCE_QUIETLY), + MIRSRC(IDE_MI_APP_ARG_EXECUTEABLE), + CMIUtilString::Format(MIRSRC(IDE_MI_APP_ARG_NO_APP_LOG), CMICmnLogMediumFile::Instance().GetFileName().c_str()), + MIRSRC(IDE_MI_APP_ARG_EXECUTABLE), Index: patches/lldbmi_s_support.v4.patch =================================================================== --- /dev/null +++ patches/lldbmi_s_support.v4.patch @@ -0,0 +1,561 @@ +Index: test/tools/lldb-mi/TestMiStartupOptions.py +=================================================================== +--- test/tools/lldb-mi/TestMiStartupOptions.py (revision 0) ++++ test/tools/lldb-mi/TestMiStartupOptions.py (working copy) +@@ -0,0 +1,210 @@ ++""" ++Test that the lldb-mi driver handle startup options correctly ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiStartupOptionsTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_sourceoption(self): ++ """Test that 'lldb-mi --interpreter' can execute a prepared file which passed via --source option.""" ++ import pexpect ++ self.buildDefault() ++ ++ # Prepared source file ++ sourcefile = "main.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # after '-file-exec-and-symbols a.out' ++ child.expect_exact("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # after '-break-insert -f main' ++ child.expect_exact("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ ++ # after '-exec-run' ++ child.expect_exact("-exec-run") ++ child.expect("\^running") ++ ++ # after '-exec-next --thread 1 --frame 0' ++ child.expect_exact("-exec-next --thread 1 --frame 0") ++ child.expect("\^running") ++ ++ # after '-break-insert -f main.c:23' ++ self.line = line_number('main.c', '//BP_atest') ++ child.expect_exact("-break-insert -f main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # after '-exec-continue' ++ child.expect_exact("-exec-continue") ++ child.expect("\^running") ++ ++ # after '-data-evaluate-expression a' ++ child.expect_exact("-data-evaluate-expression a") ++ child.expect("\^done,value=\"10\"") ++ ++ # after '-gdb-exit' ++ child.expect_exact("-gdb-exit") ++ child.expect("\^exit") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_sourceoption_without_exit(self): ++ """Test that 'lldb-mi --interpreter' can execute user's commands after initial commands were executed.""" ++ import pexpect ++ self.buildDefault() ++ ++ # Prepared source file ++ sourcefile = "main-no-exit.micmds" ++ ++ # The default lldb-mi prompt. ++ prompt = "(gdb)" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # after '-file-exec-and-symbols a.out' ++ child.expect_exact("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # after '-break-insert -f main' ++ child.expect_exact("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ ++ # after '-exec-run' ++ child.expect_exact("-exec-run") ++ child.expect("\^running") ++ ++ # after '-exec-next --thread 1 --frame 0' ++ child.expect_exact("-exec-next --thread 1 --frame 0") ++ child.expect("\^running") ++ ++ # after '-break-insert -f main.c:23' ++ self.line = line_number('main.c', '//BP_atest') ++ child.expect_exact("-break-insert -f main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"2\"") ++ ++ # after '-exec-continue' ++ child.expect_exact("-exec-continue") ++ child.expect("\^running") ++ ++ # after execution of --source start_script ++ # check that lldb-mi is ready ++ #child.expect_exact(prompt) #FIXME requires 'prompt' patch ++ ++ # try to evaluate 'a' expression ++ child.sendline("-data-evaluate-expression a") ++ child.expect("\^done,value=\"10\"") ++ #child.expect_exact(prompt) #FIXME requires 'prompt' patch ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_sourceoption_with_error(self): ++ """Test that 'lldb-mi --interpreter' stops execution of initial commands in case of error.""" ++ import pexpect ++ self.buildDefault() ++ ++ # Prepared source file ++ sourcefile = "main-error.micmds" ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter --source %s' % (self.lldbMiExec, sourcefile)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # after '-file-exec-and-symbols a.out' ++ child.expect_exact("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # after '-break-ins -f main' ++ child.expect_exact("-break-ins -f main") ++ child.expect("\^error") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/main-error.micmds +=================================================================== +--- test/tools/lldb-mi/main-error.micmds (revision 0) ++++ test/tools/lldb-mi/main-error.micmds (working copy) +@@ -0,0 +1,2 @@ ++-file-exec-and-symbols a.out ++-break-ins -f main +Index: test/tools/lldb-mi/main-no-exit.micmds +=================================================================== +--- test/tools/lldb-mi/main-no-exit.micmds (revision 0) ++++ test/tools/lldb-mi/main-no-exit.micmds (working copy) +@@ -0,0 +1,6 @@ ++-file-exec-and-symbols a.out ++-break-insert -f main ++-exec-run ++-exec-next --thread 1 --frame 0 ++-break-insert -f main.c:23 ++-exec-continue +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 225612) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -18,7 +18,9 @@ + { + int a, b; + printf("argc=%d\n", argc); ++ //BP_argctest + a = a_MyFunction(); ++ //BP_atest -- it must be at line #23 (or fix it in main*.micmds) + b = b_MyFunction(); + //BP_localstest + if (doloop) +Index: test/tools/lldb-mi/main.micmds +=================================================================== +--- test/tools/lldb-mi/main.micmds (revision 0) ++++ test/tools/lldb-mi/main.micmds (working copy) +@@ -0,0 +1,8 @@ ++-file-exec-and-symbols a.out ++-break-insert -f main ++-exec-run ++-exec-next --thread 1 --frame 0 ++-break-insert -f main.c:23 ++-exec-continue ++-data-evaluate-expression a ++-gdb-exit +Index: tools/lldb-mi/MICmdCmdMiscellanous.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdMiscellanous.cpp (revision 225612) ++++ tools/lldb-mi/MICmdCmdMiscellanous.cpp (working copy) +@@ -84,7 +84,7 @@ + CMICmdCmdGdbExit::Execute(void) + { + CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag(true); +- const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Detach(); ++ const lldb::SBError sbErr = m_rLLDBDebugSessionInfo.m_lldbProcess.Stop(); + // Do not check for sbErr.Fail() here, m_lldbProcess is likely !IsValid() + + return MIstatus::success; +Index: tools/lldb-mi/MICmnResources.cpp +=================================================================== +--- tools/lldb-mi/MICmnResources.cpp (revision 225612) ++++ tools/lldb-mi/MICmnResources.cpp (working copy) +@@ -82,6 +82,9 @@ + {IDE_MI_APP_ARG_EXECUTEABLE, "--executable\n\tUse the MI Driver in MI mode for the debugging the specified\n\texecutable. Any LLDB " + "command line options are ignored even\n\tif the MI Driver falls through to the LLDB driver. " + "(Depends\n\ton the build configuration see MICmnConfig.h)\n\tNormally specified from the command line."}, ++ {IDE_MI_APP_ARG_SOURCE, "-s \n--source \n\t" ++ "Tells the debugger to read in and execute the lldb commands in the\n\t" ++ "given file, after any file provided on the command line has been\n\tloaded."}, + {IDE_MI_APP_ARG_NO_APP_LOG, "--noLog\n\tUse this argument to tell the MI Driver not to update it's log\n\tfile '%s'."}, + {IDE_MI_APP_ARG_EXAMPLE, "Example MI command:\n\t3-info-gdb-mi-command gdb-set\n\t3^done,command={exists=\"true\"}"}, + {IDE_MI_APP_ARG_EXECUTABLE, "executable (NOT IMPLEMENTED)\n\tThe file path to the executable i.e. '\"C:\\My Dev\\foo.exe\"'."}, +Index: tools/lldb-mi/MICmnResources.h +=================================================================== +--- tools/lldb-mi/MICmnResources.h (revision 225612) ++++ tools/lldb-mi/MICmnResources.h (working copy) +@@ -89,6 +89,7 @@ + IDE_MI_APP_ARG_VERSION_LONG, + IDE_MI_APP_ARG_INTERPRETER, + IDE_MI_APP_ARG_EXECUTEABLE, ++ IDE_MI_APP_ARG_SOURCE, + IDE_MI_APP_ARG_NO_APP_LOG, + IDE_MI_APP_ARG_EXAMPLE, + IDE_MI_APP_ARG_EXECUTABLE, +Index: tools/lldb-mi/MIDriver.cpp +=================================================================== +--- tools/lldb-mi/MIDriver.cpp (revision 225612) ++++ tools/lldb-mi/MIDriver.cpp (working copy) +@@ -22,6 +22,7 @@ + // Third party headers: + #include // va_list, va_start, var_end + #include ++#include + #include + + // In-house headers: +@@ -41,6 +42,7 @@ + #include "MICmdArgValFile.h" + #include "MICmdArgValString.h" + #include "MICmnConfig.h" ++#include "MICmnLLDBDebugSessionInfo.h" + + // Instantiations: + #if _DEBUG +@@ -68,6 +70,7 @@ + , m_eCurrentDriverState(eDriverState_NotRunning) + , m_bHaveExecutableFileNamePathOnCmdLine(false) + , m_bDriverDebuggingArgExecutable(false) ++ , m_bHaveCommandFileNamePathOnCmdLine(false) + { + } + +@@ -410,16 +413,17 @@ + + //++ ------------------------------------------------------------------------------------ + // Details: Check the arguments that were passed to this program to make sure they are +-// valid and to get their argument values (if any). The following are options +-// that are only handled by *this driver: ++// valid and to get their argument values (if any). The following are the only ++// options handled by this driver: + // --executable ++// --source or -s + // The application's options --interpreter and --executable in code act very similar. + // The --executable is necessary to differentiate whither the MI Driver is being +-// using by a client i.e. Eclipse or from the command line. Eclipse issues the option ++// using by a client (e.g. Eclipse) or from the command line. Eclipse issues the option + // --interpreter and also passes additional arguments which can be interpreted as an +-// executable if called from the command line. Using --executable tells the MI +-// Driver is being called the command line and that the executable argument is indeed +-// a specified executable an so actions commands to set up the executable for a ++// executable if called from the command line. Using --executable tells the MI Driver ++// it is being called from the command line and that the executable argument is indeed ++// a specified executable and should so actions commands to set up the executable for a + // debug session. Using --interpreter on the commnd line does not action additional + // commands to initialise a debug session and so be able to launch the process. + // Type: Overridden. +@@ -451,20 +455,40 @@ + + if (bHaveArgs) + { +- // Search right to left to look for the executable ++ // Search right to left to look for filenames + for (MIint i = argc - 1; i > 0; i--) + { + const CMIUtilString strArg(argv[i]); + const CMICmdArgValFile argFile; ++ ++ // Check for a filename + if (argFile.IsFilePath(strArg) || CMICmdArgValString(true, false, true).IsStringArg(strArg)) + { ++ // Is this the command file for the '-s' or '--source' options? ++ const CMIUtilString strPrevArg(argv[i - 1]); ++ if (strPrevArg.compare("-s") == 0 || strPrevArg.compare("--source") == 0) ++ { ++ m_strCmdLineArgCommandFileNamePath = argFile.GetFileNamePath(strArg); ++ m_bHaveCommandFileNamePathOnCmdLine = true; ++ i--; // skip '-s' on the next loop ++ continue; ++ } ++ // Else, must be the executable + bHaveExecutableFileNamePath = true; + m_strCmdLineArgExecuteableFileNamePath = argFile.GetFileNamePath(strArg); + m_bHaveExecutableFileNamePathOnCmdLine = true; + } +- // This argument is also check for in CMIDriverMgr::ParseArgs() +- if (0 == strArg.compare("--executable")) // Used to specify that there is executable argument also on the command line +- { // See fn description. ++ // Report error if no command file was specified for the '-s' or '--source' options ++ else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) ++ { ++ vwbExiting = true; ++ const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str()); ++ errStatus.SetErrorString(errMsg.c_str()); ++ break; ++ } ++ // This argument is also checked for in CMIDriverMgr::ParseArgs() ++ else if (strArg.compare("--executable") == 0) // Used to specify that there is executable argument also on the command line ++ { // See fn description. + bHaveExecutableLongOption = true; + } + } +@@ -611,18 +635,28 @@ + // App is not quitting currently + m_bExitApp = false; + ++ bool bOk = MIstatus::success; + // CODETAG_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION + #if MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION + if (HaveExecutableFileNamePathOnCmdLine()) + { +- if (!LocalDebugSessionStartupInjectCommands()) ++ if (!LocalDebugSessionStartupExecuteCommands()) + { ++ bOk = MIstatus::failure; + SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION)); +- return MIstatus::failure; ++ const bool bForceExit = true; ++ SetExitApplicationFlag(bForceExit); + } + } + #endif // MICONFIG_ENABLE_MI_DRIVER_MI_MODE_CMDLINE_ARG_EXECUTABLE_DEBUG_SESSION + ++ // Handle source file ++ if (m_bHaveCommandFileNamePathOnCmdLine) ++ { ++ const bool bAsyncMode = false; ++ bOk = ExecuteCommandFile(bAsyncMode); ++ } ++ + // While the app is active + while (!m_bExitApp) + { +@@ -643,7 +677,7 @@ + // Ensure that a new line is sent as the last act of the dying driver + m_rStdOut.WriteMIResponse("\n", false); + +- return MIstatus::success; ++ return bOk; + } + + //++ ------------------------------------------------------------------------------------ +@@ -774,7 +808,7 @@ + // const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) ); + // m_pLog->WriteLog( msg ); + +- return MIstatus::success; ++ return MIstatus::failure; + } + + //++ ------------------------------------------------------------------------------------ +@@ -1292,11 +1326,11 @@ + // Throws: None. + //-- + bool +-CMIDriver::LocalDebugSessionStartupInjectCommands(void) ++CMIDriver::LocalDebugSessionStartupExecuteCommands(void) + { +- const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str())); +- +- return InjectMICommand(strCmd); ++ const CMIUtilString strCommand(CMIUtilString::Format("-file-exec-and-symbols \"%s\"", m_strCmdLineArgExecuteableFileNamePath.c_str())); ++ const bool bOk = CMICmnStreamStdout::TextToStdout(strCommand); ++ return (bOk && InterpretCommand(strCommand)); + } + + //++ ------------------------------------------------------------------------------------ +@@ -1327,3 +1361,59 @@ + { + return m_bDriverDebuggingArgExecutable; + } ++ ++// Helper function for CMIDriver::DoMainLoop. ++// Execute commands from source file in specific mode, and set exit-flag if needed ++//++ ------------------------------------------------------------------------------------ ++// Details: Execute commands from prepared source file ++// Type: Method. ++// Args: vbAsyncMode - (R) True = execute commands in asynchronous mode, false = otherwise. ++// Return: MIstatus::success - Functionality succeeded. ++// MIstatus::failure - Functionality failed. ++// Throws: None. ++//-- ++bool ++CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) ++{ ++ std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str()); ++ if (!ifsStartScript.is_open()) ++ { ++ const CMIUtilString errMsg( ++ CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN), m_strCmdLineArgCommandFileNamePath.c_str())); ++ SetErrorDescription(errMsg.c_str()); ++ const bool bForceExit = true; ++ SetExitApplicationFlag(bForceExit); ++ return MIstatus::failure; ++ } ++ ++ // Switch lldb to synchronous mode ++ CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const bool bAsyncSetting = rSessionInfo.m_rLldbDebugger.GetAsync(); ++ rSessionInfo.m_rLldbDebugger.SetAsync(vbAsyncMode); ++ ++ // Execute commands from file ++ bool bOk = MIstatus::success; ++ CMIUtilString strCommand; ++ while (std::getline(ifsStartScript, strCommand)) ++ { ++ // Print command ++ CMICmnStreamStdout::TextToStdout(strCommand); ++ ++ // Execute if no error ++ if (bOk) ++ bOk = InterpretCommand(strCommand); ++ ++ // Break if there is ++ if (!bOk) ++ { ++ const bool bForceExit = true; ++ SetExitApplicationFlag(bForceExit); ++ break; ++ } ++ } ++ ++ // Switch lldb back to initial mode ++ rSessionInfo.m_rLldbDebugger.SetAsync(bAsyncSetting); ++ ++ return bOk; ++} +Index: tools/lldb-mi/MIDriver.h +=================================================================== +--- tools/lldb-mi/MIDriver.h (revision 225612) ++++ tools/lldb-mi/MIDriver.h (working copy) +@@ -153,7 +153,8 @@ + bool InitClientIDEToMIDriver(void) const; + bool InitClientIDEEclipse(void) const; + bool QueueMICommand(const CMIUtilString &vMICmd); +- bool LocalDebugSessionStartupInjectCommands(void); ++ bool LocalDebugSessionStartupExecuteCommands(void); ++ bool ExecuteCommandFile(const bool vbAsyncMode); + + // Overridden: + private: +@@ -175,8 +176,10 @@ + CMICmnLLDBDebugger &m_rLldbDebugger; + CMICmnStreamStdout &m_rStdOut; + DriverState_e m_eCurrentDriverState; +- bool m_bHaveExecutableFileNamePathOnCmdLine; // True = Yes executable given as one of the parameters to the MI Driver, false = not found ++ bool m_bHaveExecutableFileNamePathOnCmdLine; // True = yes, executable given as one of the parameters to the MI Driver, false = not found + CMIUtilString m_strCmdLineArgExecuteableFileNamePath; +- bool m_bDriverDebuggingArgExecutable; // True = The MI Driver (MI mode) is debugging executable passed as argument, false = running via +- // a client i.e Eclipse ++ bool m_bDriverDebuggingArgExecutable; // True = the MI Driver (MI mode) is debugging executable passed as argument, ++ // false = running via a client (e.g. Eclipse) ++ bool m_bHaveCommandFileNamePathOnCmdLine; // True = file with initial commands given as one of the parameters to the MI Driver, false = not found ++ CMIUtilString m_strCmdLineArgCommandFileNamePath; + }; +Index: tools/lldb-mi/MIDriverMgr.cpp +=================================================================== +--- tools/lldb-mi/MIDriverMgr.cpp (revision 225612) ++++ tools/lldb-mi/MIDriverMgr.cpp (working copy) +@@ -686,6 +686,7 @@ + MIRSRC(IDE_MI_APP_ARG_VERSION), + MIRSRC(IDE_MI_APP_ARG_VERSION_LONG), + MIRSRC(IDE_MI_APP_ARG_INTERPRETER), ++ MIRSRC(IDE_MI_APP_ARG_SOURCE), + MIRSRC(IDE_MI_APP_ARG_EXECUTEABLE), + CMIUtilString::Format(MIRSRC(IDE_MI_APP_ARG_NO_APP_LOG), CMICmnLogMediumFile::Instance().GetFileName().c_str()), + MIRSRC(IDE_MI_APP_ARG_EXECUTABLE), Index: patches/lldbmi_shlibs_added_removed_notification_support.patch =================================================================== --- /dev/null +++ patches/lldbmi_shlibs_added_removed_notification_support.patch @@ -0,0 +1,695 @@ +Index: include/lldb/API/SBEvent.h +=================================================================== +--- include/lldb/API/SBEvent.h (revision 228328) ++++ include/lldb/API/SBEvent.h (working copy) +@@ -78,6 +78,7 @@ + friend class SBBreakpoint; + friend class SBDebugger; + friend class SBProcess; ++ friend class SBTarget; + friend class SBThread; + friend class SBWatchpoint; + +Index: include/lldb/API/SBFileSpec.h +=================================================================== +--- include/lldb/API/SBFileSpec.h (revision 228328) ++++ include/lldb/API/SBFileSpec.h (working copy) +@@ -10,6 +10,8 @@ + #ifndef LLDB_SBFileSpec_h_ + #define LLDB_SBFileSpec_h_ + ++#include ++ + #include "lldb/API/SBDefines.h" + + namespace lldb { +@@ -54,6 +56,9 @@ + uint32_t + GetPath (char *dst_path, size_t dst_len) const; + ++ std::string ++ GetPath () const; ++ + static int + ResolvePath (const char *src_path, char *dst_path, size_t dst_len); + +Index: include/lldb/API/SBModule.h +=================================================================== +--- include/lldb/API/SBModule.h (revision 228328) ++++ include/lldb/API/SBModule.h (working copy) +@@ -111,7 +111,21 @@ + //------------------------------------------------------------------ + bool + SetRemoteInstallFileSpec (lldb::SBFileSpec &file); +- ++ ++ //------------------------------------------------------------------ ++ /// Get accessor for the symbol file specification. ++ /// ++ /// When debugging an object file an additional debug information can ++ /// be provided in separate file. Therefore if you debugging something ++ /// like '/usr/lib/liba.dylib' then debug information can be located ++ /// in folder like '/usr/lib/liba.dylib.dSYM/'. ++ /// ++ /// @return ++ /// A const reference to the file specification object. ++ //------------------------------------------------------------------ ++ lldb::SBFileSpec ++ GetSymbolFileFileSpec () const; ++ + lldb::ByteOrder + GetByteOrder (); + +@@ -318,6 +332,9 @@ + GetVersion (uint32_t *versions, + uint32_t num_versions); + ++ lldb::SBAddress ++ GetObjectFileHeaderAddress() const; ++ + private: + friend class SBAddress; + friend class SBFrame; +Index: include/lldb/API/SBTarget.h +=================================================================== +--- include/lldb/API/SBTarget.h (revision 228328) ++++ include/lldb/API/SBTarget.h (working copy) +@@ -187,7 +187,19 @@ + + bool + IsValid() const; ++ ++ static bool ++ EventIsTargetEvent (const lldb::SBEvent &event); ++ ++ static lldb::SBTarget ++ GetTargetFromEvent (const lldb::SBEvent &event); + ++ static uint32_t ++ GetNumModulesFromEvent (const lldb::SBEvent &event); ++ ++ static lldb::SBModule ++ GetModuleAtIndexFromEvent (const uint32_t idx, const lldb::SBEvent &event); ++ + static const char * + GetBroadcasterClassName (); + +Index: include/lldb/Target/Target.h +=================================================================== +--- include/lldb/Target/Target.h (revision 228328) ++++ include/lldb/Target/Target.h (working copy) +@@ -474,35 +474,49 @@ + class TargetEventData : public EventData + { + public: ++ TargetEventData (const lldb::TargetSP &target_sp); + ++ TargetEventData (const lldb::TargetSP &target_sp, const ModuleList &module_list); ++ ++ virtual ++ ~TargetEventData(); ++ + static const ConstString & + GetFlavorString (); + + virtual const ConstString & +- GetFlavor () const; +- +- TargetEventData (const lldb::TargetSP &new_target_sp); +- +- lldb::TargetSP & +- GetTarget() ++ GetFlavor () const + { +- return m_target_sp; ++ return TargetEventData::GetFlavorString (); + } + +- virtual +- ~TargetEventData(); +- + virtual void + Dump (Stream *s) const; + +- static const lldb::TargetSP +- GetTargetFromEvent (const lldb::EventSP &event_sp); +- + static const TargetEventData * +- GetEventDataFromEvent (const Event *event_sp); ++ GetEventDataFromEvent (const Event *event_ptr); + ++ static lldb::TargetSP ++ GetTargetFromEvent (const Event *event_ptr); ++ ++ static ModuleList ++ GetModuleListFromEvent (const Event *event_ptr); ++ ++ const lldb::TargetSP & ++ GetTarget() const ++ { ++ return m_target_sp; ++ } ++ ++ const ModuleList & ++ GetModuleList() const ++ { ++ return m_module_list; ++ } ++ + private: + lldb::TargetSP m_target_sp; ++ ModuleList m_module_list; + + DISALLOW_COPY_AND_ASSIGN (TargetEventData); + }; +Index: source/API/SBFileSpec.cpp +=================================================================== +--- source/API/SBFileSpec.cpp (revision 228328) ++++ source/API/SBFileSpec.cpp (working copy) +@@ -169,7 +169,21 @@ + return result; + } + ++std::string ++SBFileSpec::GetPath () const ++{ ++ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + ++ std::string result = m_opaque_ap->GetPath (); ++ ++ if (log) ++ log->Printf ("SBFileSpec(%p)::GetPath () => %s", ++ static_cast(m_opaque_ap.get()), ++ result.c_str()); ++ ++ return result; ++} ++ + const lldb_private::FileSpec * + SBFileSpec::operator->() const + { +Index: source/API/SBModule.cpp +=================================================================== +--- source/API/SBModule.cpp (revision 228328) ++++ source/API/SBModule.cpp (working copy) +@@ -178,6 +178,15 @@ + return false; + } + ++lldb::SBFileSpec ++SBModule::GetSymbolFileFileSpec () const ++{ ++ SBFileSpec sb_file_spec; ++ ModuleSP module_sp (GetSP ()); ++ if (module_sp) ++ sb_file_spec.SetFileSpec (module_sp->GetSymbolFileFileSpec()); ++ return sb_file_spec; ++} + + const uint8_t * + SBModule::GetUUIDBytes () const +@@ -690,3 +699,16 @@ + } + } + ++SBAddress ++SBModule::GetObjectFileHeaderAddress() const ++{ ++ lldb::SBAddress sb_addr; ++ ModuleSP module_sp (GetSP ()); ++ if (module_sp) ++ { ++ ObjectFile *objfile_ptr = module_sp->GetObjectFile(); ++ if (objfile_ptr) ++ sb_addr.ref() = objfile_ptr->GetHeaderAddress(); ++ } ++ return sb_addr; ++} +Index: source/API/SBTarget.cpp +=================================================================== +--- source/API/SBTarget.cpp (revision 228328) ++++ source/API/SBTarget.cpp (working copy) +@@ -13,8 +13,9 @@ + + #include "lldb/lldb-public.h" + ++#include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBDebugger.h" +-#include "lldb/API/SBBreakpoint.h" ++#include "lldb/API/SBEvent.h" + #include "lldb/API/SBExpressionOptions.h" + #include "lldb/API/SBFileSpec.h" + #include "lldb/API/SBListener.h" +@@ -324,6 +325,32 @@ + { + } + ++bool ++SBTarget::EventIsTargetEvent (const SBEvent &event) ++{ ++ return Target::TargetEventData::GetEventDataFromEvent(event.get()) != NULL; ++} ++ ++SBTarget ++SBTarget::GetTargetFromEvent (const SBEvent &event) ++{ ++ return Target::TargetEventData::GetTargetFromEvent (event.get()); ++} ++ ++uint32_t ++SBTarget::GetNumModulesFromEvent (const SBEvent &event) ++{ ++ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get()); ++ return module_list.GetSize(); ++} ++ ++SBModule ++SBTarget::GetModuleAtIndexFromEvent (const uint32_t idx, const SBEvent &event) ++{ ++ const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get()); ++ return SBModule(module_list.GetModuleAtIndex(idx)); ++} ++ + const char * + SBTarget::GetBroadcasterClassName () + { +Index: source/Core/Module.cpp +=================================================================== +--- source/Core/Module.cpp (revision 228328) ++++ source/Core/Module.cpp (working copy) +@@ -1047,6 +1047,17 @@ + Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + m_symfile_ap.reset(SymbolVendor::FindPlugin(shared_from_this(), feedback_strm)); + m_did_load_symbol_vendor = true; ++ // Update symbol file specification. ++ if (m_symfile_ap) ++ { ++ SymbolFile *symbol_file = m_symfile_ap->GetSymbolFile(); ++ if (symbol_file) ++ { ++ ObjectFile *obj_file = symbol_file->GetObjectFile(); ++ if (obj_file) ++ m_symfile_spec = obj_file->GetFileSpec(); ++ } ++ } + } + } + return m_symfile_ap.get(); +Index: source/Target/Target.cpp +=================================================================== +--- source/Target/Target.cpp (revision 228328) ++++ source/Target/Target.cpp (working copy) +@@ -1211,8 +1211,7 @@ + { + m_process_sp->ModulesDidLoad (module_list); + } +- // TODO: make event data that packages up the module_list +- BroadcastEvent (eBroadcastBitModulesLoaded, NULL); ++ BroadcastEvent (eBroadcastBitModulesLoaded, new TargetEventData (this->shared_from_this(), module_list)); + } + } + +@@ -1232,7 +1231,7 @@ + } + + m_breakpoint_list.UpdateBreakpoints (module_list, true, false); +- BroadcastEvent(eBroadcastBitSymbolsLoaded, NULL); ++ BroadcastEvent (eBroadcastBitSymbolsLoaded, new TargetEventData (this->shared_from_this(), module_list)); + } + } + +@@ -1243,8 +1242,7 @@ + { + UnloadModuleSections (module_list); + m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations); +- // TODO: make event data that packages up the module_list +- BroadcastEvent (eBroadcastBitModulesUnloaded, NULL); ++ BroadcastEvent (eBroadcastBitModulesUnloaded, new TargetEventData (this->shared_from_this(), module_list)); + } + } + +@@ -3263,48 +3261,37 @@ + //---------------------------------------------------------------------- + // Target::TargetEventData + //---------------------------------------------------------------------- +-const ConstString & +-Target::TargetEventData::GetFlavorString () ++ ++Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp) : ++ EventData (), ++ m_target_sp (target_sp), ++ m_module_list () + { +- static ConstString g_flavor ("Target::TargetEventData"); +- return g_flavor; + } + +-const ConstString & +-Target::TargetEventData::GetFlavor () const ++Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp, const ModuleList &module_list) : ++ EventData (), ++ m_target_sp (target_sp), ++ m_module_list (module_list) + { +- return TargetEventData::GetFlavorString (); + } + +-Target::TargetEventData::TargetEventData (const lldb::TargetSP &new_target_sp) : +- EventData(), +- m_target_sp (new_target_sp) ++Target::TargetEventData::~TargetEventData() + { + } + +-Target::TargetEventData::~TargetEventData() ++const ConstString & ++Target::TargetEventData::GetFlavorString () + { +- ++ static ConstString g_flavor ("Target::TargetEventData"); ++ return g_flavor; + } + + void + Target::TargetEventData::Dump (Stream *s) const + { +- + } + +-const TargetSP +-Target::TargetEventData::GetTargetFromEvent (const lldb::EventSP &event_sp) +-{ +- TargetSP target_sp; +- +- const TargetEventData *data = GetEventDataFromEvent (event_sp.get()); +- if (data) +- target_sp = data->m_target_sp; +- +- return target_sp; +-} +- + const Target::TargetEventData * + Target::TargetEventData::GetEventDataFromEvent (const Event *event_ptr) + { +@@ -3317,3 +3304,22 @@ + return NULL; + } + ++TargetSP ++Target::TargetEventData::GetTargetFromEvent (const Event *event_ptr) ++{ ++ TargetSP target_sp; ++ const TargetEventData *event_data = GetEventDataFromEvent (event_ptr); ++ if (event_data) ++ target_sp = event_data->m_target_sp; ++ return target_sp; ++} ++ ++ModuleList ++Target::TargetEventData::GetModuleListFromEvent (const Event *event_ptr) ++{ ++ ModuleList module_list; ++ const TargetEventData *event_data = GetEventDataFromEvent (event_ptr); ++ if (event_data) ++ module_list = event_data->m_module_list; ++ return module_list; ++} +Index: tools/lldb-mi/MICmnLLDBDebugger.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugger.cpp (revision 228328) ++++ tools/lldb-mi/MICmnLLDBDebugger.cpp (working copy) +@@ -293,7 +293,9 @@ + } + + const CMIUtilString strDbgId("CMICmnLLDBDebugger1"); +- MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged; ++ MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged | lldb::SBTarget::eBroadcastBitModulesLoaded | ++ lldb::SBTarget::eBroadcastBitModulesUnloaded | lldb::SBTarget::eBroadcastBitWatchpointChanged | ++ lldb::SBTarget::eBroadcastBitSymbolsLoaded; + bool bOk = RegisterForEvent(strDbgId, CMIUtilString(lldb::SBTarget::GetBroadcasterClassName()), eventMask); + + eventMask = lldb::SBThread::eBroadcastBitStackChanged; +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 228328) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -20,10 +20,12 @@ + //-- + + // Third party headers: ++#include "lldb/API/SBAddress.h" + #include "lldb/API/SBEvent.h" + #include "lldb/API/SBProcess.h" + #include "lldb/API/SBBreakpoint.h" + #include "lldb/API/SBStream.h" ++#include "lldb/API/SBTarget.h" + #include "lldb/API/SBThread.h" + #include "lldb/API/SBCommandInterpreter.h" + #include "lldb/API/SBCommandReturnObject.h" +@@ -147,6 +149,11 @@ + vrbHandledEvent = true; + bOk = HandleEventSBThread(vEvent); + } ++ else if (lldb::SBTarget::EventIsTargetEvent(vEvent)) ++ { ++ vrbHandledEvent = true; ++ bOk = HandleEventSBTarget(vEvent); ++ } + + return bOk; + } +@@ -565,6 +572,165 @@ + } + + //++ ------------------------------------------------------------------------------------ ++// Details: Handle a LLDB SBTarget event. ++// Type: Method. ++// Args: vEvent - (R) An LLDB broadcast event. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleEventSBTarget(const lldb::SBEvent &vEvent) ++{ ++ if (!ChkForStateChanges()) ++ return MIstatus::failure; ++ ++ bool bOk = MIstatus::success; ++ const MIchar *pEventType = ""; ++ const MIuint nEventType = vEvent.GetType(); ++ switch (nEventType) ++ { ++ case lldb::SBTarget::eBroadcastBitBreakpointChanged: ++ pEventType = "eBroadcastBitBreakpointChanged"; ++ break; ++ case lldb::SBTarget::eBroadcastBitModulesLoaded: ++ pEventType = "eBroadcastBitModulesLoaded"; ++ bOk = HandleTargetEventBroadcastBitModulesLoaded(vEvent); ++ break; ++ case lldb::SBTarget::eBroadcastBitModulesUnloaded: ++ pEventType = "eBroadcastBitModulesUnloaded"; ++ bOk = HandleTargetEventBroadcastBitModulesUnloaded(vEvent); ++ break; ++ case lldb::SBTarget::eBroadcastBitWatchpointChanged: ++ pEventType = "eBroadcastBitWatchpointChanged"; ++ break; ++ case lldb::SBTarget::eBroadcastBitSymbolsLoaded: ++ pEventType = "eBroadcastBitSymbolsLoaded"; ++ break; ++ default: ++ { ++ const CMIUtilString msg(CMIUtilString::Format(MIRSRC(IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT), "SBTarget", (MIuint)nEventType)); ++ SetErrorDescription(msg); ++ return MIstatus::failure; ++ } ++ } ++ m_pLog->WriteLog(CMIUtilString::Format("##### An SBTarget event occurred: %s", pEventType)); ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Print to stdout "=shlibs-added,shlib-info=[key=\"value\"...]" ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent) ++{ ++ static MIuint s_nModulesLoadedNumber(0); ++ const MIuint nSize(lldb::SBTarget::GetNumModulesFromEvent(vEvent)); ++ bool bOk = MIstatus::success; ++ for (MIuint nIndex(0); bOk && (nIndex < nSize); ++nIndex) ++ { ++ const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); ++ CMICmnMIValueList miValueList(true); ++ bOk = MiHelpGetModuleInfo(sbModule, ++s_nModulesLoadedNumber, miValueList); ++ const CMICmnMIValueResult miValueResult("shlib-info", miValueList); ++ const CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, miValueResult); ++ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); ++ } ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Print to stdout "=shlibs-removed,shlib-info=[key=\"value\"...]" ++// Type: Method. ++// Args: None. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent) ++{ ++ static MIuint s_nModulesUnloadedNumber(0); ++ const MIuint nSize(lldb::SBTarget::GetNumModulesFromEvent(vEvent)); ++ bool bOk = MIstatus::success; ++ for (MIuint nIndex(0); bOk && (nIndex < nSize); ++nIndex) ++ { ++ const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); ++ CMICmnMIValueList miValueList(true); ++ bOk = MiHelpGetModuleInfo(sbModule, ++s_nModulesUnloadedNumber, miValueList); ++ const CMICmnMIValueResult miValueResult("shlib-info", miValueList); ++ const CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, miValueResult); ++ bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); ++ } ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ ++// Details: Build module information for shlib-info "[num=\"%ld\",name=\"%s\",dyld-addr=\"%#lx\",reason=\"dyld\",path=\"%s\",loaded_addr=\"%#lx\",dsym-objpath=\"%s\"]" ++// Type: Method. ++// Args: vwrMiValueList - (W) MI value list object. ++// Return: MIstatus::success - Functional succeeded. ++// MIstatus::failure - Functional failed. ++// Throws: None. ++//-- ++bool ++CMICmnLLDBDebuggerHandleEvents::MiHelpGetModuleInfo(const lldb::SBModule &vModule, const MIuint nModuleNum, ++ CMICmnMIValueList &vwrMiValueList) ++{ ++ bool bOk = MIstatus::success; ++ ++ // Build "num" field ++ const CMIUtilString strNum(CMIUtilString::Format("%ld", nModuleNum)); ++ const CMICmnMIValueConst miValueConst(strNum); ++ const CMICmnMIValueResult miValueResult("num", miValueConst); ++ bOk = bOk && vwrMiValueList.Add(miValueResult); ++ // Build "name" field ++ const CMICmnMIValueConst miValueConst2(vModule.GetPlatformFileSpec().GetFilename()); ++ const CMICmnMIValueResult miValueResult2("name", miValueConst2); ++ bOk = bOk && vwrMiValueList.Add(miValueResult2); ++ // Build "dyld-addr" field ++ const lldb::SBAddress sbAddress(vModule.GetObjectFileHeaderAddress()); ++ const CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); ++ const lldb::addr_t nLoadAddress(sbAddress.GetLoadAddress(rSessionInfo.GetTarget())); ++ const CMIUtilString strDyldAddr(CMIUtilString::Format("%#lx", nLoadAddress)); ++ const CMICmnMIValueConst miValueConst3(nLoadAddress != LLDB_INVALID_ADDRESS ? strDyldAddr : "-"); ++ const CMICmnMIValueResult miValueResult3("dyld-addr", miValueConst3); ++ bOk = bOk && vwrMiValueList.Add(miValueResult3); ++ // Build "reason" field ++ const CMICmnMIValueConst miValueConst4("dyld"); ++ const CMICmnMIValueResult miValueResult4("reason", miValueConst4); ++ bOk = bOk && vwrMiValueList.Add(miValueResult4); ++ // Build "path" field ++ const CMIUtilString strPlatformPath(vModule.GetPlatformFileSpec().GetPath().c_str()); ++ const CMICmnMIValueConst miValueConst5(strPlatformPath); ++ const CMICmnMIValueResult miValueResult5("path", miValueConst5); ++ bOk = bOk && vwrMiValueList.Add(miValueResult5); ++ // Build "loaded_addr" field ++ const CMIUtilString strLoadedAddr(CMIUtilString::Format("%#lx", nLoadAddress)); ++ const CMICmnMIValueConst miValueConst6(nLoadAddress != LLDB_INVALID_ADDRESS ? strDyldAddr : "-"); ++ const CMICmnMIValueResult miValueResult6("loaded_addr", miValueConst6); ++ bOk = bOk && vwrMiValueList.Add(miValueResult6); ++ // Build "dsym-objpath" field ++ const CMIUtilString strSymbolFilePath(vModule.GetSymbolFileFileSpec().GetPath().c_str()); ++ if (!CMIUtilString::Compare(strPlatformPath, strSymbolFilePath)) ++ { ++ const CMICmnMIValueConst miValueConst7(strSymbolFilePath); ++ const CMICmnMIValueResult miValueResult7("dsym-objpath", miValueConst7); ++ bOk = bOk && vwrMiValueList.Add(miValueResult7); ++ } ++ ++ return bOk; ++} ++ ++//++ ------------------------------------------------------------------------------------ + // Details: Handle a LLDB SBCommandInterpreter event. + // Type: Method. + // Args: vEvent - (R) An LLDB command interpreter event. +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (revision 228328) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h (working copy) +@@ -23,6 +23,7 @@ + + // In-house headers: + #include "MICmnBase.h" ++#include "MICmnMIValueList.h" + #include "MICmnMIValueTuple.h" + #include "MIUtilSingletonBase.h" + +@@ -66,6 +67,7 @@ + bool HandleEventSBBreakpointAdded(const lldb::SBEvent &vEvent); + bool HandleEventSBBreakpointLocationsAdded(const lldb::SBEvent &vEvent); + bool HandleEventSBProcess(const lldb::SBEvent &vEvent, bool &vrbExitAppEvent); ++ bool HandleEventSBTarget(const lldb::SBEvent &vEvent); + bool HandleEventSBThread(const lldb::SBEvent &vEvent); + bool HandleEventSBThreadBitStackChanged(const lldb::SBEvent &vEvent); + bool HandleEventSBThreadSuspended(const lldb::SBEvent &vEvent); +@@ -78,6 +80,10 @@ + bool HandleProcessEventStopReasonBreakpoint(void); + bool HandleProcessEventStopSignal(bool &vwrbShouldBrk); + bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent); ++ bool HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent); ++ bool HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent); ++ bool MiHelpGetModuleInfo(const lldb::SBModule &vModule, const MIuint nModuleNum, ++ CMICmnMIValueList &vwrMiValueList); + bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple); + bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord); + bool MiOutOfBandRecordToStdout(const CMICmnMIOutOfBandRecord &vrMiResultRecord); +Index: tools/lldb-mi/MICmnMIOutOfBandRecord.cpp +=================================================================== +--- tools/lldb-mi/MICmnMIOutOfBandRecord.cpp (revision 228328) ++++ tools/lldb-mi/MICmnMIOutOfBandRecord.cpp (working copy) +@@ -36,7 +36,8 @@ + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "thread-group-started"}, + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "thread-created"}, + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "thread-exited"}, +- {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "thread-selected"}}; ++ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, "shlibs-added"}, ++ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, "shlibs-removed"}}; + CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_constMapAsyncRecordTextToToken = { + {CMICmnMIOutOfBandRecord::eOutOfBand_Running, "*"}, + {CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, "*"}, +@@ -49,7 +50,9 @@ + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupStarted, "="}, + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "="}, + {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "="}, +- {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "="}}; ++ {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "="}, ++ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, "="}, ++ {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, "="}}; + + //++ ------------------------------------------------------------------------------------ + // Details: CMICmnMIOutOfBandRecord constructor. +Index: tools/lldb-mi/MICmnMIOutOfBandRecord.h +=================================================================== +--- tools/lldb-mi/MICmnMIOutOfBandRecord.h (revision 228328) ++++ tools/lldb-mi/MICmnMIOutOfBandRecord.h (working copy) +@@ -73,6 +73,8 @@ + eOutOfBand_ThreadCreated, + eOutOfBand_ThreadExited, + eOutOfBand_ThreadSelected, ++ eOutOfBand_TargetModulesLoaded, ++ eOutOfBand_TargetModulesUnloaded, + eOutOfBand_count // Always the last one + }; + Index: patches/lldbmi_stacklistlocals_shows_global_vars.patch =================================================================== --- /dev/null +++ patches/lldbmi_stacklistlocals_shows_global_vars.patch @@ -0,0 +1,13 @@ +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 223055) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -600,7 +600,7 @@ + MIunused(nFrames); + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x0110; ++ const MIuint maskVarTypes = 0x0100; + if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + Index: patches/lldbmi_stacklistlocals_shows_global_vars.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_stacklistlocals_shows_global_vars.v2.patch @@ -0,0 +1,297 @@ +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 0) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -0,0 +1,121 @@ ++""" ++Test that the lldb-mi driver works with -stack-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiStackTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_stackargs(self): ++ """Test that 'lldb-mi --interpreter' can shows arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert --file main.c:23") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test arguments ++ child.sendline("-stack-list-arguments 0") ++ child.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_locals(self): ++ """Test that 'lldb-mi --interpreter' can shows local variables.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert --file main.c:23") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test locals ++ child.sendline("-stack-list-locals 0") ++ child.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 223355) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -432,7 +432,7 @@ + { + lldb::SBFrame frame = thread.GetFrameAtIndex(i); + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%d", i)); +@@ -600,7 +600,7 @@ + MIunused(nFrames); + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x0110; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals; + if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 223355) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -254,7 +254,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = eVariableType_Arguments; + if (!MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +@@ -327,7 +327,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = eVariableType_Arguments; + if (!MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +@@ -647,10 +647,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -663,10 +660,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); + const MIuint nArgs = listArg.GetSize(); + for (MIuint i = 0; bOk && (i < nArgs); i++) +@@ -690,10 +687,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -706,10 +700,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + const MIuint nMaxRecusiveDepth = 10; + MIuint nCurrentRecursiveDepth = 0; + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); +@@ -730,10 +724,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -746,10 +737,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + const MIuint nMaxRecusiveDepth = 10; + MIuint nCurrentRecursiveDepth = 0; + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 223355) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -103,6 +103,19 @@ + MIuint m_nBrkPtThreadId; // Restrict the breakpoint to the specified thread-id + }; + ++ // Enumerations: ++ public: ++ //++ =================================================================== ++ // Details: The type of variable used by MIResponseFormVariableInfo family functions. ++ //-- ++ enum VariableType_e ++ { ++ eVariableType_InScope = (1u << 0), // In scope only. ++ eVariableType_Statics = (1u << 1), // Statics. ++ eVariableType_Locals = (1u << 2), // Locals. ++ eVariableType_Arguments = (1u << 3) // Arguments. ++ }; ++ + // Typedefs: + public: + typedef std::vector VecActiveThreadId_t; +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223355) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -1077,7 +1077,7 @@ + if (bOk) + { + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList); + + CMICmnMIValueTuple miValueTuple; +@@ -1153,7 +1153,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + CMICmnMIValueTuple miValueTuple; Index: patches/lldbmi_stacklistlocals_shows_global_vars.v3.patch =================================================================== --- /dev/null +++ patches/lldbmi_stacklistlocals_shows_global_vars.v3.patch @@ -0,0 +1,310 @@ +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 0) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -0,0 +1,122 @@ ++""" ++Test that the lldb-mi driver works with -stack-xxx commands ++""" ++ ++import os ++import unittest2 ++import lldb ++from lldbtest import * ++ ++class MiStackTestCase(TestBase): ++ ++ mydir = TestBase.compute_mydir(__file__) ++ myexe = "a.out" ++ ++ @classmethod ++ def classCleanup(cls): ++ """Cleanup the test byproducts.""" ++ try: ++ os.remove("child_send.txt") ++ os.remove("child_read.txt") ++ os.remove(cls.myexe) ++ except: ++ pass ++ ++ @lldbmi_test ++ def test_lldbmi_stackargs(self): ++ """Test that 'lldb-mi --interpreter' can shows arguments.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ child.sendline("-break-insert -f main") ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test arguments ++ child.sendline("-stack-list-arguments 0") ++ child.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++ @lldbmi_test ++ def test_lldbmi_locals(self): ++ """Test that 'lldb-mi --interpreter' can shows local variables.""" ++ import pexpect ++ self.buildDefault() ++ ++ # So that the child gets torn down after the test. ++ self.child = pexpect.spawn('%s --interpreter' % (self.lldbMiExec)) ++ child = self.child ++ child.setecho(True) ++ # Turn on logging for input/output to/from the child. ++ with open('child_send.txt', 'w') as f_send: ++ with open('child_read.txt', 'w') as f_read: ++ child.logfile_send = f_send ++ child.logfile_read = f_read ++ ++ # Load executable ++ child.sendline("-file-exec-and-symbols %s" % (self.myexe)) ++ child.expect("\^done") ++ ++ # Run to main ++ self.line = line_number('main.c', '//BP_localstest') ++ child.sendline("-break-insert --file main.c:%d" % (self.line)) ++ child.expect("\^done,bkpt={number=\"1\"") ++ child.sendline("-exec-run") ++ child.expect("\^running") ++ child.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test locals ++ child.sendline("-stack-list-locals 0") ++ child.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") ++ ++ # Now that the necessary logging is done, restore logfile to None to ++ # stop further logging. ++ child.logfile_send = None ++ child.logfile_read = None ++ ++ with open('child_send.txt', 'r') as fs: ++ if self.TraceOn(): ++ print "\n\nContents of child_send.txt:" ++ print fs.read() ++ with open('child_read.txt', 'r') as fr: ++ from_child = fr.read() ++ if self.TraceOn(): ++ print "\n\nContents of child_read.txt:" ++ print from_child ++ ++if __name__ == '__main__': ++ import atexit ++ lldb.SBDebugger.Initialize() ++ atexit.register(lambda: lldb.SBDebugger.Terminate()) ++ unittest2.main() +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 223470) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -20,6 +20,7 @@ + printf("argc=%d\n", argc); + a = a_MyFunction(); + b = b_MyFunction(); ++ //BP_localstest + if (doloop) + infloop(); + if (argc > 1 && *argv[1] == 'l') { +Index: tools/lldb-mi/MICmdCmdStack.cpp +=================================================================== +--- tools/lldb-mi/MICmdCmdStack.cpp (revision 223470) ++++ tools/lldb-mi/MICmdCmdStack.cpp (working copy) +@@ -432,7 +432,7 @@ + { + lldb::SBFrame frame = thread.GetFrameAtIndex(i); + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + if (!rSessionInfo.MIResponseFormVariableInfo3(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%d", i)); +@@ -600,7 +600,7 @@ + MIunused(nFrames); + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x0110; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Locals; + if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (revision 223470) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp (working copy) +@@ -254,7 +254,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = eVariableType_Arguments; + if (!MIResponseFormVariableInfo(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +@@ -327,7 +327,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = eVariableType_Arguments; + if (!MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + +@@ -647,10 +647,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -663,10 +660,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); + const MIuint nArgs = listArg.GetSize(); + for (MIuint i = 0; bOk && (i < nArgs); i++) +@@ -690,10 +687,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -706,10 +700,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + const MIuint nMaxRecusiveDepth = 10; + MIuint nCurrentRecursiveDepth = 0; + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); +@@ -730,10 +724,7 @@ + // tuple type object past in. + // Type: Method. + // Args: vrFrame - (R) LLDB thread object. +-// vMaskVarTypes - (R) 0x1000 = arguments, +-// 0x0100 = locals, +-// 0x0010 = statics, +-// 0x0001 = in scope only. ++// vMaskVarTypes - (R) Construed according to VariableType_e. + // vwrMIValueList - (W) MI value list object. + // Return: MIstatus::success - Functional succeeded. + // MIstatus::failure - Functional failed. +@@ -746,10 +737,10 @@ + bool bOk = MIstatus::success; + lldb::SBFrame &rFrame = const_cast(vrFrame); + +- const bool bArg = (vMaskVarTypes & 0x1000); +- const bool bLocals = (vMaskVarTypes & 0x0100); +- const bool bStatics = (vMaskVarTypes & 0x0010); +- const bool bInScopeOnly = (vMaskVarTypes & 0x0001); ++ const bool bArg = (vMaskVarTypes & eVariableType_Arguments); ++ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); ++ const bool bStatics = (vMaskVarTypes & eVariableType_Statics); ++ const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); + const MIuint nMaxRecusiveDepth = 10; + MIuint nCurrentRecursiveDepth = 0; + lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); +Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (revision 223470) ++++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h (working copy) +@@ -103,6 +103,19 @@ + MIuint m_nBrkPtThreadId; // Restrict the breakpoint to the specified thread-id + }; + ++ // Enumerations: ++ public: ++ //++ =================================================================== ++ // Details: The type of variable used by MIResponseFormVariableInfo family functions. ++ //-- ++ enum VariableType_e ++ { ++ eVariableType_InScope = (1u << 0), // In scope only. ++ eVariableType_Statics = (1u << 1), // Statics. ++ eVariableType_Locals = (1u << 2), // Locals. ++ eVariableType_Arguments = (1u << 3) // Arguments. ++ }; ++ + // Typedefs: + public: + typedef std::vector VecActiveThreadId_t; +Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +=================================================================== +--- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (revision 223470) ++++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp (working copy) +@@ -1077,7 +1077,7 @@ + if (bOk) + { + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + bOk = rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList); + + CMICmnMIValueTuple miValueTuple; +@@ -1153,7 +1153,7 @@ + + // Function args + CMICmnMIValueList miValueList(true); +- const MIuint maskVarTypes = 0x1000; ++ const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments; + if (!rSession.MIResponseFormVariableInfo2(frame, maskVarTypes, miValueList)) + return MIstatus::failure; + CMICmnMIValueTuple miValueTuple; Index: patches/lldbmi_update_tests.patch =================================================================== --- /dev/null +++ patches/lldbmi_update_tests.patch @@ -0,0 +1,1262 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 228146) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -18,7 +18,7 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- self.runCmd("-break-insert -f a_MyFunction") ++ self.runCmd("-break-insert -f b_MyFunction") + self.expect("\^done,bkpt={number=\"1\"") + + self.runCmd("-exec-run") +@@ -40,7 +40,7 @@ + self.expect("\^done") + + # Find the line number to break inside main() and set +- # pending BP. ++ # pending BP + line = line_number('main.c', '//BP_source') + self.runCmd("-break-insert -f main.c:%d" % line) + self.expect("\^done,bkpt={number=\"1\"") +@@ -70,15 +70,15 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol +- self.runCmd("-break-insert a_MyFunction") ++ # Break on symbol ++ self.runCmd("-break-insert b_MyFunction") + self.expect("\^done,bkpt={number=\"2\"") + + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source ++ # Break on source + line = line_number('main.c', '//BP_source') + self.runCmd("-break-insert main.c:%d" % line) + self.expect("\^done,bkpt={number=\"3\"") +@@ -87,7 +87,7 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit ++ # Run to exit + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"exited-normally\"") +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,88 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiDataTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_data_disassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-disassemble: try to disassemble some address ++ self.runCmd("-data-disassemble -s 0x0 -e 0x0 -- 0") ++ self.expect("\^done,asm_insns=\[") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-data-list-register-names doesn't work properly") ++ def test_lldbmi_data_list_register_names(self): ++ """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-list-register-names: try to get all registers ++ self.runCmd("-data-list-register-names") ++ self.expect("\^done,register-names=\[\".+\",") ++ ++ # Test -data-list-register-names: try to get specified registers ++ self.runCmd("-data-list-register-names 0") ++ self.expect("\^done,register-names=\[\".+\"\]") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-data-list-register-values doesn't work properly") ++ def test_lldbmi_data_list_register_values(self): ++ """Test that 'lldb-mi --interpreter' works for -data-list-register-values.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-list-register-values: try to get all registers ++ self.runCmd("-data-list-register-values x") ++ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"") ++ ++ # Test -data-list-register-values: try to get specified registers ++ self.runCmd("-data-list-register-values x 0") ++ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"}\]") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 228146) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -18,7 +18,7 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- #run to main ++ # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + +@@ -26,7 +26,7 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to program return (marked BP_source) ++ # Run to program return (marked BP_source) + line = line_number('main.c', '//BP_source') + self.runCmd("-break-insert main.c:%d" % line) + self.expect("\^done,bkpt={number=\"2\"") +@@ -35,55 +35,60 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #print non-existant variable ++ # Print non-existant variable + #self.runCmd("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} + #self.expect("error") + #self.runCmd("-data-evaluate-expression undef") #FIXME: gets value="undef" + #self.expect("error") ++ self.runCmd("-interpreter-exec command \"print undef\"") ++ self.expect("undeclared identifier") + +- #print global "g_MyVar" +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" ++ # Print global "g_MyVar" ++ self.runCmd("-var-create var1 --frame 0 * g_MyVar") #FIXME: shows name=" + self.expect("value=\"3\",type=\"int\"") + #self.runCmd("-var-evaluate-expression var1") #FIXME: gets var1 does not exist + self.runCmd("-var-show-attributes var1") + self.expect("status=\"editable\"") + self.runCmd("-var-delete var1") + self.expect("\^done") +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") ++ self.runCmd("-var-create var1 --frame 0 * g_MyVar") + self.expect("value=\"3\",type=\"int\"") + +- #print static "s_MyVar" and modify ++ # Print static "s_MyVar" and modify + self.runCmd("-data-evaluate-expression s_MyVar") + self.expect("value=\"30\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") ++ self.runCmd("-var-create var3 --frame 0 * \"s_MyVar=3\"") + self.expect("value=\"3\",type=\"int\"") + self.runCmd("-data-evaluate-expression \"s_MyVar=30\"") + self.expect("value=\"30\"") ++ self.runCmd("-interpreter-exec command \"p s_MyVar\"") ++ self.expect("= 30") + +- #print local "b" and modify ++ # Print local "b" and modify + self.runCmd("-data-evaluate-expression b") + self.expect("value=\"20\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"b=3\"") ++ self.runCmd("-var-create var3 --frame 0 * \"b=3\"") + self.expect("value=\"3\",type=\"int\"") + self.runCmd("-data-evaluate-expression \"b=20\"") + self.expect("value=\"20\"") ++ self.runCmd("-interpreter-exec command \"print b\"") ++ self.expect("= 20") + +- #print "a + b" ++ # Print "a + b" + self.runCmd("-data-evaluate-expression \"a + b\"") + self.expect("value=\"30\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"a + b\"") ++ self.runCmd("-var-create var3 --frame 0 * \"a + b\"") + self.expect("value=\"30\",type=\"int\"") ++ self.runCmd("-interpreter-exec command \"print a + b\"") ++ self.expect("= 30") + +- #print "argv[0]" ++ # Print "argv[0]" + self.runCmd("-data-evaluate-expression \"argv[0]\"") + self.expect("value=\"0x") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") ++ self.runCmd("-var-create var3 --frame 0 * \"argv[0]\"") + self.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") ++ self.runCmd("-interpreter-exec command \"print argv[0]\"") ++ self.expect("= 0x") + +- #run to exit +- self.runCmd("-exec-continue") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"exited-normally\"") +- + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,440 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiExecTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-exec-abort isn't implemented") ++ def test_lldbmi_exec_abort(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-abort.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Test that -exec-abort fails on invalid process ++ self.runCmd("-exec-abort") ++ self.expect("\^error,msg=\"Command 'exec-abort'. Invalid process during debug session\"") ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments arg1") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that arguments were passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"2\"") ++ ++ # Test that program may be aborted ++ self.runCmd("-exec-abort") ++ self.expect("\^done") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ ++ # Test that program can be run again ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that arguments were passed again ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"2\"") ++ ++ # Test that program may be aborted again ++ self.runCmd("-exec-abort") ++ self.expect("\^done") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_arguments_set(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Check argc and argv to see if arg passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"5\"") ++ #self.runCmd("-data-evaluate-expression argv[1]") ++ #self.expect("\^done,value=\"--arg1\"") ++ self.runCmd("-interpreter-exec command \"print argv[1]\"") ++ self.expect("\"--arg1\"") ++ #self.runCmd("-data-evaluate-expression argv[2]") ++ #self.expect("\^done,value=\"2nd arg\"") ++ self.runCmd("-interpreter-exec command \"print argv[2]\"") ++ self.expect("\"2nd arg\"") ++ #self.runCmd("-data-evaluate-expression argv[3]") ++ #self.expect("\^done,value=\"third_arg\"") ++ self.runCmd("-interpreter-exec command \"print argv[3]\"") ++ self.expect("\"third_arg\"") ++ #self.runCmd("-data-evaluate-expression argv[4]") ++ #self.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ self.runCmd("-interpreter-exec command \"print argv[4]\"") ++ self.expect("\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_arguments_reset(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments foo bar baz") ++ self.expect("\^done") ++ self.runCmd("-exec-arguments") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Check argc to see if arg passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"1\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next(self): ++ """Test that 'lldb-mi --interpreter' works for stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test -exec-next ++ self.runCmd("-exec-next --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-next --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations ++ ++ # Test -exec-next-instruction ++ self.runCmd("-exec-next-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-next-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_step(self): ++ """Test that 'lldb-mi --interpreter' works for stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to printf call ++ line = line_number('main.c', '//BP_printf_call') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source ++ ++ # Test that -exec-step does not step into printf (which ++ # has no debug info) ++ #FIXME: is this supposed to step into printf? ++ self.runCmd("-exec-step --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step steps into a_MyFunction and back out ++ # (and that --thread is optional) ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ #FIXME: is this supposed to step into printf? ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that -exec-step steps into b_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-step steps into a_MyFunction from inside ++ # b_MyFunction (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-step --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin due to calling convention assumptions") ++ def test_lldbmi_exec_step_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations ++ ++ # Run to a_MyFunction call ++ line = line_number('main.c', '//BP_a_MyFunction_call') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction ++ self.runCmd("-exec-step-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction (and that --thread is optional) ++ self.runCmd("-exec-step-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-step-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_finish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set argument 'l' ++ self.runCmd("-exec-arguments l") ++ self.expect("\^done") ++ ++ # Set BP at a_MyFunction_call and run to BP ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Run to BP inside b_MyFunction call ++ line = line_number('b.c', '//BP_b_MyFunction') ++ self.runCmd("-break-insert -f b.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish hits BP at a_MyFunction call inside ++ # b_MyFunction (and that --thread is optional) ++ self.runCmd("-exec-finish --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction call inside ++ # b_MyFunction (and that --frame is optional) ++ self.runCmd("-exec-finish --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-finish returns from b_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-finish") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-finish --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-finish --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ #self.runCmd("-exec-finish --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ # Set BP at printf and run to BP ++ # FIXME: BP at printf not resolved and never hit! ++ self.runCmd("-interpreter-exec command \"b printf\"") #FIXME: self.runCmd("-break-insert -f printf") ++ self.expect("\^done") #FIXME: self.expect("\^done,bkpt={number=\"3\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ ## Test that -exec-finish returns from printf ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiExit.py +=================================================================== +--- test/tools/lldb-mi/TestMiExit.py (revision 0) ++++ test/tools/lldb-mi/TestMiExit.py (working copy) +@@ -0,0 +1,59 @@ ++""" ++Test that the lldb-mi driver works properly with "-gdb-exit". ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiExitTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_gdbexit(self): ++ """Test that '-gdb-exit' terminates debug session and exits.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -gdb-exit: try to exit and check that program is finished ++ self.runCmd("-gdb-exit") ++ self.expect("\^exit") ++ import pexpect ++ self.expect(pexpect.EOF) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_quit(self): ++ """Test that 'quit' exits immediately.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test quit: try to exit and check that program is finished ++ self.runCmd("quit") ++ import pexpect ++ self.expect(pexpect.EOF) ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiInterrupt.py +=================================================================== +--- test/tools/lldb-mi/TestMiInterrupt.py (revision 228146) ++++ test/tools/lldb-mi/TestMiInterrupt.py (working copy) +@@ -9,8 +9,8 @@ + class MiInterruptTestCase(lldbmi_testcase.MiTestCaseBase): + + @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") +- @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_interrupt(self): + """Test that 'lldb-mi --interpreter' interrupt and resume a looping app.""" + +@@ -19,20 +19,20 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- #run to main ++ # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #set doloop=1 and run (to loop forever) ++ # Set doloop=1 and run (to loop forever) + self.runCmd("-data-evaluate-expression \"doloop=1\"") + self.expect("value=\"1\"") + self.runCmd("-exec-continue") + self.expect("\^running") + +- #issue interrupt, set BP in loop (marked BP_loop), and resume ++ # Issue interrupt, set BP in loop (marked BP_loop), and resume + self.runCmd("-exec-interrupt") + self.expect("\*stopped,reason=\"signal-received\"") + line = line_number('loop.c', '//BP_loop') +@@ -42,13 +42,55 @@ + self.runCmd("-exec-continue") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #we should have hit BP +- #set loop=-1 so we'll exit the loop ++ # We should have hit BP ++ # Set loop=-1 so we'll exit the loop + self.runCmd("-data-evaluate-expression \"loop=-1\"") + self.expect("value=\"-1\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"exited-normally\"") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi how to send cntl-C to app?") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_cntlC(self): ++ """Test that 'lldb-mi --interpreter' cntl-C interrupts app.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set doloop=1 and run (to loop forever) ++ self.runCmd("-var-create var2 --thread 1 --frame 0 * \"doloop=1\"") ++ self.expect("value=\"1\",type=\"int\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Issue interrupt, set a bp, and resume ++ #FIXME: how to runCmd cntl-C? ++ self.runCmd("-exec-interrupt") # or cntl-c ++ self.expect("\*stopped,reason=\"signal-received\"") ++ self.runCmd("-break-insert loop.c:11") ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # We should be sitting at loop.c:12 ++ # Set loop=-1 so we'll exit the loop ++ self.runCmd("-data-evaluate-expression \"loop=-1\"") ++ self.expect("value=\"-1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiLaunch.py +=================================================================== +--- test/tools/lldb-mi/TestMiLaunch.py (revision 228146) ++++ test/tools/lldb-mi/TestMiLaunch.py (working copy) +@@ -15,7 +15,7 @@ + + self.spawnLldbMi(args = None) + +- #use no path ++ # Use no path + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +@@ -30,7 +30,7 @@ + + self.spawnLldbMi(args = None) + +- #use full path ++ # Use full path + import os + exe = os.path.join(os.getcwd(), self.myexe) + self.runCmd("-file-exec-and-symbols %s" % exe) +@@ -47,7 +47,7 @@ + + self.spawnLldbMi(args = None) + +- #use relative path ++ # Use relative path + exe = "../../" + self.mydir + "/" + self.myexe + self.runCmd("-file-exec-and-symbols %s" % exe) + self.expect("\^done") +@@ -63,7 +63,7 @@ + + self.spawnLldbMi(args = None) + +- #use non-existant path ++ # Use non-existant path + exe = "badpath/" + self.myexe + self.runCmd("-file-exec-and-symbols %s" % exe) + self.expect("\^error") +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 0) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -0,0 +1,113 @@ ++""" ++Test that the lldb-mi driver nofities user properly. ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiNotificationTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi doesn't print prompt in all cases") ++ def test_lldbmi_prompt(self): ++ """Test that 'lldb-mi --interpreter' echos '(gdb)' after commands and events.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Test that lldb-mi is ready after startup ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -file-exec-and-symbols ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -break-insert ++ self.runCmd("-break-insert -f b_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -exec-run ++ self.runCmd("-exec-run") ++ self.expect("\*running") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after BP hit ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -exec-continue ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after program exited ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D7273: requires this patch") ++ def test_lldbmi_stopped_when_stopatentry_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D7273: requires this patch") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_stopatentry_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (remote).""" ++ ++ # Prepare debugserver ++ import os, sys ++ lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver")) ++ sys.path.append(lldb_gdbserver_folder) ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 228146) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -1,45 +0,0 @@ +-""" +-Test that the lldb-mi driver can pass arguments to the app. +-""" +- +-import lldbmi_testcase +-from lldbtest import * +-import unittest2 +- +-class MiProgramArgsTestCase(lldbmi_testcase.MiTestCaseBase): +- +- @lldbmi_test +- @unittest2.skip("lldb-mi can't pass params to app.") +- @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" +- +- self.spawnLldbMi(args = None) +- +- self.runCmd("-file-exec-and-symbols %s" % self.myexe) +- self.expect("\^done") +- +- self.runCmd("settings set target.run-args l") #FIXME: args not passed +- #self.runCmd("-exec-arguments l") #FIXME: not recognized and hung lldb-mi +- +- #run to main +- self.runCmd("-break-insert -f main") +- self.expect("\^done,bkpt={number=\"1\"") +- self.runCmd("-exec-run") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"breakpoint-hit\"") +- +- #check argc to see if arg passed +- self.runCmd("-data-evaluate-expression argc") +- self.expect("value=\"2\"") +- +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- line = line_number('main.c', '//BP_argtest') +- self.runCmd("-break-insert main.c:%d" % line) +- self.expect("\^done,bkpt={number=\"2\"") +- self.runCmd("-exec-continue") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"breakpoint-hit\"") +- +-if __name__ == '__main__': +- unittest2.main() +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 228146) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -10,6 +10,7 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_stackargs(self): + """Test that 'lldb-mi --interpreter' can shows arguments.""" + +@@ -27,20 +28,21 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test arguments +- #self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work +- #self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") ++ self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") + self.runCmd("-stack-list-arguments 1") + self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_locals(self): + """Test that 'lldb-mi --interpreter' can shows local variables.""" + + self.spawnLldbMi(args = None) + + # Load executable +- self.runCmd("-file-exec-and-symbols %s" % (self.myexe)) ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main +@@ -52,10 +54,54 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test locals +- #self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work +- #self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") ++ self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work ++ self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") + self.runCmd("-stack-list-locals 1") + self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackdepth(self): ++ """Test that 'lldb-mi --interpreter' can shows depth of the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack depth ++ self.runCmd("-stack-info-depth") ++ self.expect("\^done,depth=\"[1-9]\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackframes(self): ++ """Test that 'lldb-mi --interpreter' can lists the frames on the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack frame: get frame #0 info ++ self.runCmd("-stack-list-frames 0 0") ++ self.expect("\^done,stack=\[frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\".+\"\}\]") ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 228146) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -20,7 +20,7 @@ + self.expect("000\^done") + + # Run to main +- self.runCmd("100000001-break-insert -f a_MyFunction") ++ self.runCmd("100000001-break-insert -f b_MyFunction") + self.expect("100000001\^done,bkpt={number=\"1\"") + self.runCmd("2-exec-run") + self.expect("2\^running") +@@ -31,5 +31,35 @@ + self.expect("0000000000000000000003\^running") + self.expect("\*stopped,reason=\"exited-normally\"") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi doesn't handle special chars properly") ++ def test_lldbmi_specialchars(self): ++ """Test that 'lldb-mi --interpreter' handles complicated strings.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Create alias for myexe ++ complicated_myexe = "C--mpl-x file's`s @#$%^&*()_+-={}[]| name" ++ if os.path.exists(complicated_myexe): ++ os.unlink(complicated_myexe) ++ os.symlink(self.myexe, complicated_myexe) ++ ++ try: ++ # Try to load executable with complicated filename ++ self.runCmd("-file-exec-and-symbols \"%s\"" % complicated_myexe) ++ self.expect("\^done") ++ ++ # Check that it was loaded correctly ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ finally: ++ # Clean up ++ os.unlink(complicated_myexe) ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/a.c +=================================================================== +--- test/tools/lldb-mi/a.c (revision 228146) ++++ test/tools/lldb-mi/a.c (working copy) +@@ -3,7 +3,6 @@ + int + a_MyFunction () + { +- // Set a breakpoint here. +- printf ("a is about to return 10.\n"); ++ printf ("a is about to return 10.\n"); //BP_a_MyFunction + return 10; + } +Index: test/tools/lldb-mi/b.c +=================================================================== +--- test/tools/lldb-mi/b.c (revision 228146) ++++ test/tools/lldb-mi/b.c (working copy) +@@ -1,9 +1,10 @@ + #include + ++extern int a_MyFunction(); + int + b_MyFunction () + { +- // Set a breakpoint here. ++ (void)a_MyFunction(); //BP_b_MyFunction + printf ("b is about to return 20.\n"); + return 20; + } +Index: test/tools/lldb-mi/lldbmi_testcase.py +=================================================================== +--- test/tools/lldb-mi/lldbmi_testcase.py (revision 228146) ++++ test/tools/lldb-mi/lldbmi_testcase.py (working copy) +@@ -37,5 +37,7 @@ + def runCmd(self, cmd): + self.child.sendline(cmd) + +- def expect(self, pattern, *args, **kwargs): +- self.child.expect(pattern, *args, **kwargs) ++ def expect(self, pattern, exactly=False, *args, **kwargs): ++ if exactly: ++ return self.child.expect_exact(pattern, *args, **kwargs) ++ return self.child.expect(pattern, *args, **kwargs) +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 228146) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -17,10 +17,11 @@ + int main (int argc, char const *argv[]) + { + int a, b; +- printf("argc=%d\n", argc); +- a = a_MyFunction(); +- b = b_MyFunction(); +- //BP_localstest ++ printf("argc=%d\n", argc); //BP_printf_call ++ //BP_argctest ++ a = a_MyFunction(); //BP_a_MyFunction_call ++ b = b_MyFunction(); //BP_b_MyFunction_call ++ //BP_localstest -- it must be at line #24 (or fix it in main*.micmds) + if (doloop) + infloop(); + if (argc > 1 && *argv[1] == 'l') { Index: patches/lldbmi_update_tests.v2.patch =================================================================== --- /dev/null +++ patches/lldbmi_update_tests.v2.patch @@ -0,0 +1,1327 @@ +Index: test/tools/lldb-mi/TestMiBreakpoint.py +=================================================================== +--- test/tools/lldb-mi/TestMiBreakpoint.py (revision 228146) ++++ test/tools/lldb-mi/TestMiBreakpoint.py (working copy) +@@ -18,7 +18,7 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- self.runCmd("-break-insert -f a_MyFunction") ++ self.runCmd("-break-insert -f b_MyFunction") + self.expect("\^done,bkpt={number=\"1\"") + + self.runCmd("-exec-run") +@@ -40,7 +40,7 @@ + self.expect("\^done") + + # Find the line number to break inside main() and set +- # pending BP. ++ # pending BP + line = line_number('main.c', '//BP_source') + self.runCmd("-break-insert -f main.c:%d" % line) + self.expect("\^done,bkpt={number=\"1\"") +@@ -70,15 +70,15 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on symbol +- self.runCmd("-break-insert a_MyFunction") ++ # Break on symbol ++ self.runCmd("-break-insert b_MyFunction") + self.expect("\^done,bkpt={number=\"2\"") + + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #break on source ++ # Break on source + line = line_number('main.c', '//BP_source') + self.runCmd("-break-insert main.c:%d" % line) + self.expect("\^done,bkpt={number=\"3\"") +@@ -87,7 +87,7 @@ + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to exit ++ # Run to exit + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"exited-normally\"") +Index: test/tools/lldb-mi/TestMiData.py +=================================================================== +--- test/tools/lldb-mi/TestMiData.py (revision 0) ++++ test/tools/lldb-mi/TestMiData.py (working copy) +@@ -0,0 +1,94 @@ ++""" ++Test that the lldb-mi driver works with -data-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiDataTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-data-disassemble doesn't show 'size' field") ++ def test_lldbmi_data_disassemble(self): ++ """Test that 'lldb-mi --interpreter' works for -data-disassemble.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Get an address for disassembling: use main ++ self.runCmd("-data-evaluate-expression main") ++ self.expect("\^done,value=\"0x[0-9a-f]+\"") ++ addr = int(self.child.after.split("\"")[1], 16) ++ ++ # Test -data-disassemble: try to disassemble some address ++ self.runCmd("-data-disassemble -s %#x -e %#x -- 0" % (addr, addr + 0x10)) ++ self.expect("\^done,asm_insns=\[{address=\"%#x\",func-name=\"main\",offset=\"0x0\",size=\"[1-9]\",inst=\".+\"}," % addr) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-data-list-register-names doesn't work properly") ++ def test_lldbmi_data_list_register_names(self): ++ """Test that 'lldb-mi --interpreter' works for -data-list-register-names.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-list-register-names: try to get all registers ++ self.runCmd("-data-list-register-names") ++ self.expect("\^done,register-names=\[\".+\",") ++ ++ # Test -data-list-register-names: try to get specified registers ++ self.runCmd("-data-list-register-names 0") ++ self.expect("\^done,register-names=\[\".+\"\]") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-data-list-register-values doesn't work properly") ++ def test_lldbmi_data_list_register_values(self): ++ """Test that 'lldb-mi --interpreter' works for -data-list-register-values.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -data-list-register-values: try to get all registers ++ self.runCmd("-data-list-register-values x") ++ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"") ++ ++ # Test -data-list-register-values: try to get specified registers ++ self.runCmd("-data-list-register-values x 0") ++ self.expect("\^done,register-values=\[{number=\"0\",value=\"0x[0-9a-f]+\"}\]") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiEvaluate.py +=================================================================== +--- test/tools/lldb-mi/TestMiEvaluate.py (revision 228146) ++++ test/tools/lldb-mi/TestMiEvaluate.py (working copy) +@@ -10,80 +10,103 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("evaluation doesn't work properly") + def test_lldbmi_eval(self): + """Test that 'lldb-mi --interpreter' works for evaluating.""" + + self.spawnLldbMi(args = None) + ++ # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- #run to main +- self.runCmd("-break-insert -f main") ++ # Run to program return (marked BP_source) ++ line = line_number('main.c', '//BP_source') ++ self.runCmd("-break-insert main.c:%d" % line) + self.expect("\^done,bkpt={number=\"1\"") +- + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #run to program return (marked BP_source) +- line = line_number('main.c', '//BP_source') +- self.runCmd("-break-insert main.c:%d" % line) +- self.expect("\^done,bkpt={number=\"2\"") ++ # Print non-existant variable ++ self.runCmd("-var-create var1 * undef") ++ #self.expect("\^error") #FIXME: shows undef as {...} ++ self.runCmd("-data-evaluate-expression undef") ++ self.expect("\^error,msg=\"Could not evaluate expression\"") + +- self.runCmd("-exec-continue") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"breakpoint-hit\"") +- +- #print non-existant variable +- #self.runCmd("-var-create var1 --thread 1 --frame 0 * undef") #FIXME: shows undef as {...} +- #self.expect("error") +- #self.runCmd("-data-evaluate-expression undef") #FIXME: gets value="undef" +- #self.expect("error") +- +- #print global "g_MyVar" +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") #FIXME: shows name=" +- self.expect("value=\"3\",type=\"int\"") +- #self.runCmd("-var-evaluate-expression var1") #FIXME: gets var1 does not exist +- self.runCmd("-var-show-attributes var1") +- self.expect("status=\"editable\"") +- self.runCmd("-var-delete var1") ++ # Print global "g_MyVar", modify, delete and create again ++ self.runCmd("-data-evaluate-expression g_MyVar") ++ self.expect("\^done,value=\"3\"") ++ self.runCmd("-var-create var2 * g_MyVar") ++ self.expect("\^done,name=\"var2\",numchild=\"0\",value=\"3\",type=\"int\",thread-id=\"1\",has_more=\"0\"") ++ self.runCmd("-var-evaluate-expression var2") ++ self.expect("\^done,value=\"3\"") ++ self.runCmd("-var-show-attributes var2") ++ self.expect("\^done,status=\"editable\"") ++ self.runCmd("-data-evaluate-expression \"g_MyVar=30\"") ++ self.expect("\^done,value=\"30\"") ++ self.runCmd("-var-update var2") ++ #self.expect("name=\"var2\",value=\"30\"") #FIXME -var-update doesn't work ++ self.runCmd("-var-delete var2") + self.expect("\^done") +- self.runCmd("-var-create var1 --thread 1 --frame 0 * g_MyVar") +- self.expect("value=\"3\",type=\"int\"") ++ self.runCmd("-var-create var2 * g_MyVar") ++ self.expect("\^done,name=\"var2\",numchild=\"0\",value=\"30\",type=\"int\",thread-id=\"1\",has_more=\"0\"") + +- #print static "s_MyVar" and modify ++ # Print static "s_MyVar", modify, delete and create again + self.runCmd("-data-evaluate-expression s_MyVar") +- self.expect("value=\"30\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"s_MyVar=3\"") +- self.expect("value=\"3\",type=\"int\"") +- self.runCmd("-data-evaluate-expression \"s_MyVar=30\"") +- self.expect("value=\"30\"") ++ self.expect("\^done,value=\"30\"") ++ self.runCmd("-var-create var3 * s_MyVar") ++ self.expect("\^done,name=\"var3\",numchild=\"0\",value=\"30\",type=\"int\",thread-id=\"1\",has_more=\"0\"") ++ self.runCmd("-var-evaluate-expression var3") ++ self.expect("\^done,value=\"30\"") ++ self.runCmd("-var-show-attributes var3") ++ self.expect("\^done,status=\"editable\"") ++ self.runCmd("-data-evaluate-expression \"s_MyVar=3\"") ++ self.expect("\^done,value=\"3\"") ++ self.runCmd("-var-update var3") ++ #self.expect("name=\"var3\",value=\"3\"") #FIXME -var-update doesn't work ++ self.runCmd("-var-delete var3") ++ self.expect("\^done") ++ self.runCmd("-var-create var3 * s_MyVar") ++ self.expect("\^done,name=\"var3\",numchild=\"0\",value=\"3\",type=\"int\",thread-id=\"1\",has_more=\"0\"") + +- #print local "b" and modify ++ # Print local "b", modify, delete and create again + self.runCmd("-data-evaluate-expression b") +- self.expect("value=\"20\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"b=3\"") +- self.expect("value=\"3\",type=\"int\"") +- self.runCmd("-data-evaluate-expression \"b=20\"") +- self.expect("value=\"20\"") ++ self.expect("\^done,value=\"20\"") ++ self.runCmd("-var-create var4 * b") ++ self.expect("\^done,name=\"var4\",numchild=\"0\",value=\"20\",type=\"int\",thread-id=\"1\",has_more=\"0\"") ++ self.runCmd("-var-evaluate-expression var4") ++ self.expect("\^done,value=\"20\"") ++ self.runCmd("-var-show-attributes var4") ++ self.expect("\^done,status=\"editable\"") ++ self.runCmd("-data-evaluate-expression \"b=2\"") ++ self.expect("\^done,value=\"2\"") ++ self.runCmd("-var-update var4") ++ #self.expect("name=\"var4\",value=\"2\"") #FIXME -var-update doesn't work ++ self.runCmd("-var-delete var4") ++ self.expect("\^done") ++ self.runCmd("-var-create var4 * b") ++ self.expect("\^done,name=\"var4\",numchild=\"0\",value=\"2\",type=\"int\",thread-id=\"1\",has_more=\"0\"") + +- #print "a + b" ++ # Print temp "a + b" + self.runCmd("-data-evaluate-expression \"a + b\"") +- self.expect("value=\"30\"") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"a + b\"") +- self.expect("value=\"30\",type=\"int\"") ++ self.expect("\^done,value=\"12\"") ++ self.runCmd("-var-create var5 * \"a + b\"") ++ self.expect("\^done,name=\"var5\",numchild=\"0\",value=\"12\",type=\"int\",thread-id=\"1\",has_more=\"0\"") ++ self.runCmd("-var-evaluate-expression var5") ++ self.expect("\^done,value=\"12\"") ++ self.runCmd("-var-show-attributes var5") ++ self.expect("\^done,status=\"editable\"") #FIXME editable or not? + +- #print "argv[0]" ++ # Print argument "argv[0]" + self.runCmd("-data-evaluate-expression \"argv[0]\"") +- self.expect("value=\"0x") +- self.runCmd("-var-create var3 --thread 1 --frame 0 * \"argv[0]\"") +- self.expect("numchild=\"1\",value=\"0x.*\",type=\"const char \*\"") ++ self.expect("\^done,value=\"0x[0-9a-f]+\"") ++ self.runCmd("-var-create var6 * \"argv[0]\"") ++ self.expect("\^done,name=\"var6\",numchild=\"1\",value=\"0x[0-9a-f]+\",type=\"const char \*\",thread-id=\"1\",has_more=\"0\"") ++ self.runCmd("-var-evaluate-expression var6") ++ self.expect("\^done,value=\"0x[0-9a-f]+\"") ++ self.runCmd("-var-show-attributes var6") ++ self.expect("\^done,status=\"editable\"") + +- #run to exit +- self.runCmd("-exec-continue") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"exited-normally\"") +- + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiExec.py +=================================================================== +--- test/tools/lldb-mi/TestMiExec.py (revision 0) ++++ test/tools/lldb-mi/TestMiExec.py (working copy) +@@ -0,0 +1,440 @@ ++""" ++Test that the lldb-mi driver works with -exec-xxx commands ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiExecTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-exec-abort isn't implemented") ++ def test_lldbmi_exec_abort(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-abort.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Test that -exec-abort fails on invalid process ++ self.runCmd("-exec-abort") ++ self.expect("\^error,msg=\"Command 'exec-abort'. Invalid process during debug session\"") ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments arg1") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that arguments were passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"2\"") ++ ++ # Test that program may be aborted ++ self.runCmd("-exec-abort") ++ self.expect("\^done") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ ++ # Test that program can be run again ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that arguments were passed again ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"2\"") ++ ++ # Test that program may be aborted again ++ self.runCmd("-exec-abort") ++ self.expect("\^done") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_arguments_set(self): ++ """Test that 'lldb-mi --interpreter' can pass args using -exec-arguments.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments --arg1 \"2nd arg\" third_arg fourth=\"4th arg\"") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Check argc and argv to see if arg passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"5\"") ++ #self.runCmd("-data-evaluate-expression argv[1]") ++ #self.expect("\^done,value=\"--arg1\"") ++ self.runCmd("-interpreter-exec command \"print argv[1]\"") ++ self.expect("\"--arg1\"") ++ #self.runCmd("-data-evaluate-expression argv[2]") ++ #self.expect("\^done,value=\"2nd arg\"") ++ self.runCmd("-interpreter-exec command \"print argv[2]\"") ++ self.expect("\"2nd arg\"") ++ #self.runCmd("-data-evaluate-expression argv[3]") ++ #self.expect("\^done,value=\"third_arg\"") ++ self.runCmd("-interpreter-exec command \"print argv[3]\"") ++ self.expect("\"third_arg\"") ++ #self.runCmd("-data-evaluate-expression argv[4]") ++ #self.expect("\^done,value=\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ self.runCmd("-interpreter-exec command \"print argv[4]\"") ++ self.expect("\"fourth=\\\\\\\"4th arg\\\\\\\"\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_arguments_reset(self): ++ """Test that 'lldb-mi --interpreter' can reset previously set args using -exec-arguments.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set arguments ++ self.runCmd("-exec-arguments foo bar baz") ++ self.expect("\^done") ++ self.runCmd("-exec-arguments") ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Check argc to see if arg passed ++ self.runCmd("-data-evaluate-expression argc") ++ self.expect("\^done,value=\"1\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next(self): ++ """Test that 'lldb-mi --interpreter' works for stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source. ++ ++ # Test -exec-next ++ self.runCmd("-exec-next --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"25\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"27\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-next --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_next_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations ++ ++ # Test -exec-next-instruction ++ self.runCmd("-exec-next-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --thread is optional ++ self.runCmd("-exec-next-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that --frame is optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"20\"") ++ ++ # Test that both --thread and --frame are optional ++ self.runCmd("-exec-next-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-next-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-next-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-next-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_exec_step(self): ++ """Test that 'lldb-mi --interpreter' works for stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to printf call ++ line = line_number('main.c', '//BP_printf_call') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Warning: the following is sensative to the lines in the source ++ ++ # Test that -exec-step does not step into printf (which ++ # has no debug info) ++ #FIXME: is this supposed to step into printf? ++ self.runCmd("-exec-step --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step steps into a_MyFunction and back out ++ # (and that --thread is optional) ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ #FIXME: is this supposed to step into printf? ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ self.runCmd("-exec-step --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"23\"") ++ ++ # Test that -exec-step steps into b_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-step steps into a_MyFunction from inside ++ # b_MyFunction (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-step --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin due to calling convention assumptions") ++ def test_lldbmi_exec_step_instruction(self): ++ """Test that 'lldb-mi --interpreter' works for instruction stepping into.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Warning: the following is sensative to the lines in the ++ # source and optimizations ++ ++ # Run to a_MyFunction call ++ line = line_number('main.c', '//BP_a_MyFunction_call') ++ self.runCmd("-break-insert -f main.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction ++ self.runCmd("-exec-step-instruction --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps over non branching ++ # instruction (and that --thread is optional) ++ self.runCmd("-exec-step-instruction --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*main.c\",line=\"22\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that --frame is optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that -exec-step-instruction steps into a_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-step-instruction --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"a_MyFunction\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-step-instruction --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-step-instruction --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ self.runCmd("-exec-step-instruction --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D6965: requires this patch") ++ def test_lldbmi_exec_finish(self): ++ """Test that 'lldb-mi --interpreter' works for -exec-finish.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Set argument 'l' ++ self.runCmd("-exec-arguments l") ++ self.expect("\^done") ++ ++ # Set BP at a_MyFunction_call and run to BP ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Run to BP inside b_MyFunction call ++ line = line_number('b.c', '//BP_b_MyFunction') ++ self.runCmd("-break-insert -f b.c:%d" % line) ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish hits BP at a_MyFunction call inside ++ # b_MyFunction (and that --thread is optional) ++ self.runCmd("-exec-finish --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test that -exec-finish returns from a_MyFunction call inside ++ # b_MyFunction (and that --frame is optional) ++ self.runCmd("-exec-finish --thread 1") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"b_MyFunction\"") ++ ++ # Test that -exec-finish returns from b_MyFunction ++ # (and that both --thread and --frame are optional) ++ self.runCmd("-exec-finish") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++ # Test that an invalid --thread is handled ++ self.runCmd("-exec-finish --thread 0") ++ self.expect("\^error,message=\"error: Thread index 0 is out of range") ++ self.runCmd("-exec-finish --thread 10") ++ self.expect("\^error,message=\"error: Thread index 10 is out of range") ++ ++ # Test that an invalid --frame is handled ++ # FIXME: no error is returned ++ #self.runCmd("-exec-finish --frame 10") ++ #self.expect("\^error: Frame index 10 is out of range") ++ ++ # Set BP at printf and run to BP ++ # FIXME: BP at printf not resolved and never hit! ++ self.runCmd("-interpreter-exec command \"b printf\"") #FIXME: self.runCmd("-break-insert -f printf") ++ self.expect("\^done") #FIXME: self.expect("\^done,bkpt={number=\"3\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ ## Test that -exec-finish returns from printf ++ self.runCmd("-exec-finish --thread 1 --frame 0") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"end-stepping-range\".*func=\"main\"") ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiExit.py +=================================================================== +--- test/tools/lldb-mi/TestMiExit.py (revision 0) ++++ test/tools/lldb-mi/TestMiExit.py (working copy) +@@ -0,0 +1,59 @@ ++""" ++Test that the lldb-mi driver works properly with "-gdb-exit". ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiExitTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_gdbexit(self): ++ """Test that '-gdb-exit' terminates debug session and exits.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test -gdb-exit: try to exit and check that program is finished ++ self.runCmd("-gdb-exit") ++ self.expect("\^exit") ++ import pexpect ++ self.expect(pexpect.EOF) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_quit(self): ++ """Test that 'quit' exits immediately.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test quit: try to exit and check that program is finished ++ self.runCmd("quit") ++ import pexpect ++ self.expect(pexpect.EOF) ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiInterrupt.py +=================================================================== +--- test/tools/lldb-mi/TestMiInterrupt.py (revision 228146) ++++ test/tools/lldb-mi/TestMiInterrupt.py (working copy) +@@ -9,8 +9,8 @@ + class MiInterruptTestCase(lldbmi_testcase.MiTestCaseBase): + + @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") +- @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + def test_lldbmi_interrupt(self): + """Test that 'lldb-mi --interpreter' interrupt and resume a looping app.""" + +@@ -19,20 +19,20 @@ + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +- #run to main ++ # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #set doloop=1 and run (to loop forever) ++ # Set doloop=1 and run (to loop forever) + self.runCmd("-data-evaluate-expression \"doloop=1\"") + self.expect("value=\"1\"") + self.runCmd("-exec-continue") + self.expect("\^running") + +- #issue interrupt, set BP in loop (marked BP_loop), and resume ++ # Issue interrupt, set BP in loop (marked BP_loop), and resume + self.runCmd("-exec-interrupt") + self.expect("\*stopped,reason=\"signal-received\"") + line = line_number('loop.c', '//BP_loop') +@@ -42,13 +42,55 @@ + self.runCmd("-exec-continue") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + +- #we should have hit BP +- #set loop=-1 so we'll exit the loop ++ # We should have hit BP ++ # Set loop=-1 so we'll exit the loop + self.runCmd("-data-evaluate-expression \"loop=-1\"") + self.expect("value=\"-1\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"exited-normally\"") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi how to send cntl-C to app?") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_cntlC(self): ++ """Test that 'lldb-mi --interpreter' cntl-C interrupts app.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Set doloop=1 and run (to loop forever) ++ self.runCmd("-var-create var2 --thread 1 --frame 0 * \"doloop=1\"") ++ self.expect("value=\"1\",type=\"int\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ ++ # Issue interrupt, set a bp, and resume ++ #FIXME: how to runCmd cntl-C? ++ self.runCmd("-exec-interrupt") # or cntl-c ++ self.expect("\*stopped,reason=\"signal-received\"") ++ self.runCmd("-break-insert loop.c:11") ++ self.expect("\^done,bkpt={number=\"2\"") ++ self.runCmd("-exec-continue") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # We should be sitting at loop.c:12 ++ # Set loop=-1 so we'll exit the loop ++ self.runCmd("-data-evaluate-expression \"loop=-1\"") ++ self.expect("value=\"-1\"") ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiLaunch.py +=================================================================== +--- test/tools/lldb-mi/TestMiLaunch.py (revision 228146) ++++ test/tools/lldb-mi/TestMiLaunch.py (working copy) +@@ -15,7 +15,7 @@ + + self.spawnLldbMi(args = None) + +- #use no path ++ # Use no path + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + +@@ -30,7 +30,7 @@ + + self.spawnLldbMi(args = None) + +- #use full path ++ # Use full path + import os + exe = os.path.join(os.getcwd(), self.myexe) + self.runCmd("-file-exec-and-symbols %s" % exe) +@@ -47,7 +47,7 @@ + + self.spawnLldbMi(args = None) + +- #use relative path ++ # Use relative path + exe = "../../" + self.mydir + "/" + self.myexe + self.runCmd("-file-exec-and-symbols %s" % exe) + self.expect("\^done") +@@ -63,7 +63,7 @@ + + self.spawnLldbMi(args = None) + +- #use non-existant path ++ # Use non-existant path + exe = "badpath/" + self.myexe + self.runCmd("-file-exec-and-symbols %s" % exe) + self.expect("\^error") +Index: test/tools/lldb-mi/TestMiNotification.py +=================================================================== +--- test/tools/lldb-mi/TestMiNotification.py (revision 0) ++++ test/tools/lldb-mi/TestMiNotification.py (working copy) +@@ -0,0 +1,113 @@ ++""" ++Test that the lldb-mi driver nofities user properly. ++""" ++ ++import lldbmi_testcase ++from lldbtest import * ++import unittest2 ++ ++class MiNotificationTestCase(lldbmi_testcase.MiTestCaseBase): ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi doesn't print prompt in all cases") ++ def test_lldbmi_prompt(self): ++ """Test that 'lldb-mi --interpreter' echos '(gdb)' after commands and events.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Test that lldb-mi is ready after startup ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -file-exec-and-symbols ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -break-insert ++ self.runCmd("-break-insert -f b_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -exec-run ++ self.runCmd("-exec-run") ++ self.expect("\*running") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after BP hit ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after -exec-continue ++ self.runCmd("-exec-continue") ++ self.expect("\^running") ++ self.expect(self.child_prompt, exactly = True) ++ ++ # Test that lldb-mi is ready after program exited ++ self.expect("\*stopped,reason=\"exited-normally\"") ++ self.expect(self.child_prompt, exactly = True) ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D7273: requires this patch") ++ def test_lldbmi_stopped_when_stopatentry_local(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (local).""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("reviews.llvm.org/D7273: requires this patch") ++ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") ++ def test_lldbmi_stopped_when_stopatentry_remote(self): ++ """Test that 'lldb-mi --interpreter' notifies after it was stopped on entry (remote).""" ++ ++ # Prepare debugserver ++ import os, sys ++ lldb_gdbserver_folder = os.path.abspath(os.path.join(os.path.dirname(os.getcwd()), "lldb-gdbserver")) ++ sys.path.append(lldb_gdbserver_folder) ++ import lldbgdbserverutils ++ debugserver_exe = lldbgdbserverutils.get_debugserver_exe() ++ if not debugserver_exe: ++ raise Exception("debugserver not found") ++ hostname = "localhost" ++ import random ++ port = 12000 + random.randint(0,3999) # the same as GdbRemoteTestCaseBase.get_next_port ++ import pexpect ++ debugserver_child = pexpect.spawn("%s %s:%d" % (debugserver_exe, hostname, port)) ++ ++ self.spawnLldbMi(args = None) ++ ++ # Connect to debugserver ++ self.runCmd("-interpreter-exec command \"platform select remote-macosx --sysroot /\"") ++ self.expect("\^done") ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ self.runCmd("-interpreter-exec command \"process connect connect://%s:%d\"" % (hostname, port)) ++ self.expect("\^done") ++ ++ try: ++ # Run with stop-at-entry flag ++ self.runCmd("-interpreter-exec command \"process launch -s\"") ++ self.expect("\^done") ++ ++ # Test that *stopped is printed ++ self.expect("\*stopped,reason=\"signal-received\",signal=\"17\",thread-id=\"1\",stopped-threads=\"all\"") ++ ++ finally: ++ # Clean up ++ debugserver_child.terminate(force = True) ++ ++if __name__ == '__main__': ++ unittest2.main() +Index: test/tools/lldb-mi/TestMiProgramArgs.py +=================================================================== +--- test/tools/lldb-mi/TestMiProgramArgs.py (revision 228146) ++++ test/tools/lldb-mi/TestMiProgramArgs.py (working copy) +@@ -1,45 +0,0 @@ +-""" +-Test that the lldb-mi driver can pass arguments to the app. +-""" +- +-import lldbmi_testcase +-from lldbtest import * +-import unittest2 +- +-class MiProgramArgsTestCase(lldbmi_testcase.MiTestCaseBase): +- +- @lldbmi_test +- @unittest2.skip("lldb-mi can't pass params to app.") +- @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") +- def test_lldbmi_paramargs(self): +- """Test that 'lldb-mi --interpreter' can pass arguments to the app.""" +- +- self.spawnLldbMi(args = None) +- +- self.runCmd("-file-exec-and-symbols %s" % self.myexe) +- self.expect("\^done") +- +- self.runCmd("settings set target.run-args l") #FIXME: args not passed +- #self.runCmd("-exec-arguments l") #FIXME: not recognized and hung lldb-mi +- +- #run to main +- self.runCmd("-break-insert -f main") +- self.expect("\^done,bkpt={number=\"1\"") +- self.runCmd("-exec-run") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"breakpoint-hit\"") +- +- #check argc to see if arg passed +- self.runCmd("-data-evaluate-expression argc") +- self.expect("value=\"2\"") +- +- #set BP on code which is only executed if "l" was passed correctly (marked BP_argtest) +- line = line_number('main.c', '//BP_argtest') +- self.runCmd("-break-insert main.c:%d" % line) +- self.expect("\^done,bkpt={number=\"2\"") +- self.runCmd("-exec-continue") +- self.expect("\^running") +- self.expect("\*stopped,reason=\"breakpoint-hit\"") +- +-if __name__ == '__main__': +- unittest2.main() +Index: test/tools/lldb-mi/TestMiStack.py +=================================================================== +--- test/tools/lldb-mi/TestMiStack.py (revision 228146) ++++ test/tools/lldb-mi/TestMiStack.py (working copy) +@@ -10,6 +10,7 @@ + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_stackargs(self): + """Test that 'lldb-mi --interpreter' can shows arguments.""" + +@@ -27,20 +28,21 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test arguments +- #self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work +- #self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") ++ self.runCmd("-stack-list-arguments 0") #FIXME: --no-values doesn't work ++ self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[name=\"argc\",name=\"argv\"\]}") + self.runCmd("-stack-list-arguments 1") + self.expect("\^done,stack-args=\[frame={level=\"0\",args=\[{name=\"argc\",value=\"1\"},{name=\"argv\",value=\".*\"}\]}") + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("-stack-list-locals doesn't work properly") + def test_lldbmi_locals(self): + """Test that 'lldb-mi --interpreter' can shows local variables.""" + + self.spawnLldbMi(args = None) + + # Load executable +- self.runCmd("-file-exec-and-symbols %s" % (self.myexe)) ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main +@@ -52,10 +54,54 @@ + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test locals +- #self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work +- #self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") ++ self.runCmd("-stack-list-locals 0") #FIXME: --no-values doesn't work ++ self.expect("\^done,locals=\[name=\"a\",name=\"b\"\]") + self.runCmd("-stack-list-locals 1") + self.expect("\^done,locals=\[{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackdepth(self): ++ """Test that 'lldb-mi --interpreter' can shows depth of the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack depth ++ self.runCmd("-stack-info-depth") ++ self.expect("\^done,depth=\"[1-9]\"") ++ ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ def test_lldbmi_stackframes(self): ++ """Test that 'lldb-mi --interpreter' can lists the frames on the stack.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Load executable ++ self.runCmd("-file-exec-and-symbols %s" % self.myexe) ++ self.expect("\^done") ++ ++ # Run to main ++ self.runCmd("-break-insert -f main") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ # Test stack frame: get frame #0 info ++ self.runCmd("-stack-list-frames 0 0") ++ self.expect("\^done,stack=\[frame=\{level=\"0\",addr=\".+\",func=\"main\",file=\"main\.c\",fullname=\".*main\.c\",line=\".+\"\}\]") ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/TestMiSyntax.py +=================================================================== +--- test/tools/lldb-mi/TestMiSyntax.py (revision 228146) ++++ test/tools/lldb-mi/TestMiSyntax.py (working copy) +@@ -20,7 +20,7 @@ + self.expect("000\^done") + + # Run to main +- self.runCmd("100000001-break-insert -f a_MyFunction") ++ self.runCmd("100000001-break-insert -f b_MyFunction") + self.expect("100000001\^done,bkpt={number=\"1\"") + self.runCmd("2-exec-run") + self.expect("2\^running") +@@ -31,5 +31,35 @@ + self.expect("0000000000000000000003\^running") + self.expect("\*stopped,reason=\"exited-normally\"") + ++ @lldbmi_test ++ @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") ++ @unittest2.skip("lldb-mi doesn't handle special chars properly") ++ def test_lldbmi_specialchars(self): ++ """Test that 'lldb-mi --interpreter' handles complicated strings.""" ++ ++ self.spawnLldbMi(args = None) ++ ++ # Create alias for myexe ++ complicated_myexe = "C--mpl-x file's`s @#$%^&*()_+-={}[]| name" ++ if os.path.exists(complicated_myexe): ++ os.unlink(complicated_myexe) ++ os.symlink(self.myexe, complicated_myexe) ++ ++ try: ++ # Try to load executable with complicated filename ++ self.runCmd("-file-exec-and-symbols \"%s\"" % complicated_myexe) ++ self.expect("\^done") ++ ++ # Check that it was loaded correctly ++ self.runCmd("-break-insert -f a_MyFunction") ++ self.expect("\^done,bkpt={number=\"1\"") ++ self.runCmd("-exec-run") ++ self.expect("\^running") ++ self.expect("\*stopped,reason=\"breakpoint-hit\"") ++ ++ finally: ++ # Clean up ++ os.unlink(complicated_myexe) ++ + if __name__ == '__main__': + unittest2.main() +Index: test/tools/lldb-mi/a.c +=================================================================== +--- test/tools/lldb-mi/a.c (revision 228146) ++++ test/tools/lldb-mi/a.c (working copy) +@@ -3,7 +3,6 @@ + int + a_MyFunction () + { +- // Set a breakpoint here. +- printf ("a is about to return 10.\n"); ++ printf ("a is about to return 10.\n"); //BP_a_MyFunction + return 10; + } +Index: test/tools/lldb-mi/b.c +=================================================================== +--- test/tools/lldb-mi/b.c (revision 228146) ++++ test/tools/lldb-mi/b.c (working copy) +@@ -1,9 +1,10 @@ + #include + ++extern int a_MyFunction(); + int + b_MyFunction () + { +- // Set a breakpoint here. ++ (void)a_MyFunction(); //BP_b_MyFunction + printf ("b is about to return 20.\n"); + return 20; + } +Index: test/tools/lldb-mi/lldbmi_testcase.py +=================================================================== +--- test/tools/lldb-mi/lldbmi_testcase.py (revision 228146) ++++ test/tools/lldb-mi/lldbmi_testcase.py (working copy) +@@ -37,5 +37,7 @@ + def runCmd(self, cmd): + self.child.sendline(cmd) + +- def expect(self, pattern, *args, **kwargs): +- self.child.expect(pattern, *args, **kwargs) ++ def expect(self, pattern, exactly=False, *args, **kwargs): ++ if exactly: ++ return self.child.expect_exact(pattern, *args, **kwargs) ++ return self.child.expect(pattern, *args, **kwargs) +Index: test/tools/lldb-mi/main.c +=================================================================== +--- test/tools/lldb-mi/main.c (revision 228146) ++++ test/tools/lldb-mi/main.c (working copy) +@@ -17,10 +17,11 @@ + int main (int argc, char const *argv[]) + { + int a, b; +- printf("argc=%d\n", argc); +- a = a_MyFunction(); +- b = b_MyFunction(); +- //BP_localstest ++ printf("argc=%d\n", argc); //BP_printf_call ++ //BP_argctest ++ a = a_MyFunction(); //BP_a_MyFunction_call ++ b = b_MyFunction(); //BP_b_MyFunction_call ++ //BP_localstest -- it must be at line #24 (or fix it in main*.micmds) + if (doloop) + infloop(); + if (argc > 1 && *argv[1] == 'l') { Index: patches/lldbtest_ignore_ioerror_on_theardown.patch =================================================================== --- /dev/null +++ patches/lldbtest_ignore_ioerror_on_theardown.patch @@ -0,0 +1,13 @@ +Index: test/lldbtest.py +=================================================================== +--- test/lldbtest.py (revision 224334) ++++ test/lldbtest.py (working copy) +@@ -1072,7 +1072,7 @@ + self.child.sendline('settings set interpreter.prompt-on-quit false') + self.child.sendline('quit') + self.child.expect(pexpect.EOF) +- except (ValueError, pexpect.ExceptionPexpect): ++ except (ValueError, IOError, pexpect.ExceptionPexpect): + # child is already terminated + pass + finally: Index: patches/lldbtest_ignore_ioerror_on_theardown.v2.patch =================================================================== --- /dev/null +++ patches/lldbtest_ignore_ioerror_on_theardown.v2.patch @@ -0,0 +1,13 @@ +Index: test/lldbtest.py +=================================================================== +--- test/lldbtest.py (revision 224334) ++++ test/lldbtest.py (working copy) +@@ -1072,7 +1072,7 @@ + self.child.sendline('settings set interpreter.prompt-on-quit false') + self.child.sendline('quit') + self.child.expect(pexpect.EOF) +- except (ValueError, pexpect.ExceptionPexpect): ++ except (ValueError, OSError, pexpect.ExceptionPexpect): + # child is already terminated + pass + finally: Index: scripts/Python/finish-swig-Python-LLDB.sh =================================================================== --- scripts/Python/finish-swig-Python-LLDB.sh +++ scripts/Python/finish-swig-Python-LLDB.sh @@ -167,6 +167,7 @@ fi fi +# Make symlink for darwin-debug on Darwin if [ ${OS_NAME} = "Darwin" ] && [ $MakefileCalled -ne 0 ] then # We are being built by CMake on Darwin @@ -187,6 +188,27 @@ fi fi +# Make symlink for argdumper on any platform +if [ $MakefileCalled -ne 0 ] +then + # We are being built by CMake + + if [ ! -L "${framework_python_dir}/argdumper" ] + then + if [ $Debug -eq 1 ] + then + echo "Creating symlink for argdumper" + fi + cd "${framework_python_dir}" + ln -s "../../../../bin/argdumper" argdumper + else + if [ $Debug -eq 1 ] + then + echo "${framework_python_dir}/argdumper already exists." + fi + fi +fi + create_python_package () { package_dir="${framework_python_dir}$1" package_files="$2" Index: scripts/Python/finishSwigPythonLLDB.py =================================================================== --- scripts/Python/finishSwigPythonLLDB.py +++ scripts/Python/finishSwigPythonLLDB.py @@ -70,8 +70,8 @@ strMsgFrameWkPyExists = "Python output folder '%s' already exists"; strMsgFrameWkPyMkDir = "Python output folder '%s' will be created"; strErrMsgCreateFrmWkPyDirFailed = "Unable to create directory '%s' error: %s"; -strMsglldbsoExists = "Symlink '%s' already exists"; -strMsglldbsoMk = "Creating symlink for _lldb.so (%s -> %s)"; +strMsgSymlinkExists = "Symlink for '%s' already exists"; +strMsgSymlinkMk = "Creating symlink for %s (%s -> %s)"; strErrMsgCpLldbpy = "copying lldb to lldb package directory"; strErrMsgCreatePyPkgMissingSlash = "Parameter 3 fn create_py_pkg() missing slash"; strErrMsgMkLinkExecute = "Command mklink failed: %s"; @@ -218,120 +218,159 @@ strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; return (bOk, strMsg); + +#++--------------------------------------------------------------------------- +# Details: Make the symbolic link on a Windows platform. +# Args: vstrSrcFile - (R) Source file name. +# vstrTargetFile - (R) Destination file name. +# Returns: Bool - True = function success, False = failure. +# Str - Error description on task failure. +# Throws: None. +#-- +def make_symlink_windows( vstrSrcPath, vstrTargetPath ): + print "Making symlink from %s to %s" % (vstrSrcPath, vstrTargetPath); + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_windows()" ); + bOk = True; + strErrMsg = ""; + + try: + csl = ctypes.windll.kernel32.CreateHardLinkW + csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) + csl.restype = ctypes.c_ubyte + if csl(vstrTargetPath, vstrSrcPath, 0) == 0: + raise ctypes.WinError() + except Exception as e: + if e.errno != 17: + bOk = False; + strErrMsg = "WinError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); + strErrMsg += " Src:'%s' Target:'%s'" % (vstrSrcPath, vstrTargetPath); + + return (bOk, strErrMsg); #++--------------------------------------------------------------------------- -# Details: Make the symbolic that the script bridge for Python will need in -# the Python framework directory. Code for specific to Windows. +# Details: Make the symbolic link on a UNIX style platform. +# Args: vstrSrcFile - (R) Source file name. +# vstrTargetFile - (R) Destination file name. +# Returns: Bool - True = function success, False = failure. +# Str - Error description on task failure. +# Throws: None. +#-- +def make_symlink_other_platforms( vstrSrcPath, vstrTargetPath ): + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); + bOk = True; + strErrMsg = ""; + + try: + os.symlink( vstrSrcPath, vstrTargetPath ); + except OSError as e: + bOk = False; + strErrMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); + strErrMsg += " Src:'%s' Target:'%s'" % (vstrSrcPath, vstrTargetPath); + except: + bOk = False; + strErrMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; + + return (bOk, strErrMsg); + +#++--------------------------------------------------------------------------- +# Details: Make the symbolic link. # Args: vDictArgs - (R) Program input parameters. # vstrFrameworkPythonDir - (R) Python framework directory. -# vstrDllName - (R) File name for _lldb.dll. +# vstrSrcFile - (R) Source file name. +# vstrTargetFile - (R) Destination file name. # Returns: Bool - True = function success, False = failure. # Str - Error description on task failure. # Throws: None. #-- -def make_symlink_windows( vDictArgs, vstrFrameworkPythonDir, vstrDllName ): - dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_windows()" ); +def make_symlink( vDictArgs, vstrFrameworkPythonDir, vstrSrcFile, vstrTargetFile ): + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink()" ); bOk = True; - strMsg = ""; - + strErrMsg = ""; bDbg = vDictArgs.has_key( "-d" ); - strTarget = vstrDllName; - # When importing an extension module using a debug version of python, you - # write, for example, "import foo", but the interpreter searches for - # "foo_d.pyd" - if vDictArgs["--buildConfig"].lower() == "debug": - strTarget += "_d"; - strTarget += ".pyd"; - strDLLPath = "%s\\%s" % (vstrFrameworkPythonDir, strTarget); - strTarget = os.path.normcase( strDLLPath ); + strTarget = "%s/%s" % (vstrFrameworkPythonDir, vstrTargetFile); + strTarget = os.path.normcase( strTarget ); strSrc = ""; os.chdir( vstrFrameworkPythonDir ); bMakeFileCalled = vDictArgs.has_key( "-m" ); + eOSType = utilsOsType.determine_os_type(); if not bMakeFileCalled: - strSrc = os.path.normcase( "../../../LLDB" ); + return (bOk, strErrMsg); else: - strLibFileExtn = ".dll"; - strSrc = os.path.normcase( "../../../bin/liblldb%s" % strLibFileExtn ); + strSrc = os.path.normcase( "../../../%s" % vstrSrcFile ); - if os.path.isfile( strTarget ): + if eOSType == utilsOsType.EnumOsType.Unknown: + bOk = False; + strErrMsg = strErrMsgOsTypeUnknown; + elif eOSType == utilsOsType.EnumOsType.Windows: + if os.path.isfile( strTarget ): + if bDbg: + print strMsgSymlinkExists % vstrTargetFile; if bDbg: - print strMsglldbsoExists % strTarget; - return (bOk, strMsg); + print strMsgSymlinkMk % (vstrTargetFile, strSrc, strTarget); + bOk, strErrMsg = make_symlink_windows( strSrc, + strTarget ); + else: + if os.path.islink( strTarget ): + if bDbg: + print strMsgSymlinkExists % vstrTargetFile; + if bDbg: + print strMsgSymlinkMk % (vstrTargetFile, strSrc, strTarget); + return (bOk, strErrMsg); + bOk, strErrMsg = make_symlink_other_platforms( strSrc, + strTarget ); - if bDbg: - print strMsglldbsoMk % (os.path.abspath(strSrc), os.path.abspath(strTarget)); - - try: - csl = ctypes.windll.kernel32.CreateHardLinkW - csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) - csl.restype = ctypes.c_ubyte - if csl(strTarget, strSrc, 0) == 0: - raise ctypes.WinError() - except Exception as e: - bOk = False; - strMsg = "WinError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); - strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); + return (bOk, strErrMsg); - return (bOk, strMsg); - #++--------------------------------------------------------------------------- -# Details: Make the symbolic link that the script bridge for Python will need in -# the Python framework directory. Code for all platforms apart from -# Windows. +# Details: Make the symbolic that the script bridge for Python will need in +# the Python framework directory. # Args: vDictArgs - (R) Program input parameters. # vstrFrameworkPythonDir - (R) Python framework directory. -# vstrSoName - (R) File name for _lldb.so. +# vstrLiblldbName - (R) File name for _lldb library. # Returns: Bool - True = function success, False = failure. # Str - Error description on task failure. # Throws: None. #-- -def make_symlink_other_platforms( vDictArgs, vstrFrameworkPythonDir, vstrSoPath ): - dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); +def make_symlink_liblldb( vDictArgs, vstrFrameworkPythonDir, vstrLiblldbFileName ): + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_liblldb()" ); bOk = True; - strMsg = ""; - bDbg = vDictArgs.has_key( "-d" ); - strTarget = vstrSoPath + ".so"; - strSoPath = "%s/%s" % (vstrFrameworkPythonDir, strTarget); - strTarget = os.path.normcase( strSoPath ); + strErrMsg = ""; + strTarget = vstrLiblldbFileName strSrc = ""; - - os.chdir( vstrFrameworkPythonDir ); + + eOSType = utilsOsType.determine_os_type(); + if eOSType == utilsOsType.EnumOsType.Windows: + # When importing an extension module using a debug version of python, you + # write, for example, "import foo", but the interpreter searches for + # "foo_d.pyd" + if vDictArgs["--buildConfig"].lower() == "debug": + strTarget += "_d"; + strTarget += ".pyd"; + else: + strTarget += ".so"; + bMakeFileCalled = vDictArgs.has_key( "-m" ); if not bMakeFileCalled: - strSrc = os.path.normcase( "../../../LLDB" ); + strSrc = "lib/LLDB"; else: strLibFileExtn = ""; - eOSType = utilsOsType.determine_os_type(); - if eOSType == utilsOsType.EnumOsType.Linux: - strLibFileExtn = ".so"; - elif eOSType == utilsOsType.EnumOsType.Darwin: - strLibFileExtn = ".dylib"; - strSrc = os.path.normcase( "../../../liblldb%s" % strLibFileExtn ); + if eOSType == utilsOsType.EnumOsType.Windows: + strLibFileExtn = ".dll"; + strSrc = "bin/liblldb%s" % strLibFileExtn; + else: + if eOSType == utilsOsType.EnumOsType.Linux: + strLibFileExtn = ".so"; + elif eOSType == utilsOsType.EnumOsType.Darwin: + strLibFileExtn = ".dylib"; + strSrc = "lib/liblldb%s" % strLibFileExtn; + + bOk, strErrMsg = make_symlink( vDictArgs, vstrFrameworkPythonDir, strSrc, strTarget ); + + return (bOk, strErrMsg); - if os.path.islink( strTarget ): - if bDbg: - print strMsglldbsoExists % strTarget; - return (bOk, strMsg); - - if bDbg: - print strMsglldbsoMk; - - try: - os.symlink( strSrc, strTarget ); - except OSError as e: - bOk = False; - strMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); - strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); - except: - bOk = False; - strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; - - return (bOk, strMsg); - #++--------------------------------------------------------------------------- -# Details: Make the symbolic link to the darwin-debug. Code for all platforms -# apart from Windows. +# Details: Make the symbolic link to the darwin-debug. # Args: vDictArgs - (R) Program input parameters. # vstrFrameworkPythonDir - (R) Python framework directory. # vstrDarwinDebugFileName - (R) File name for darwin-debug. @@ -340,41 +379,51 @@ # Throws: None. #-- def make_symlink_darwin_debug( vDictArgs, vstrFrameworkPythonDir, vstrDarwinDebugFileName ): - dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_other_platforms()" ); + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_darwin_debug()" ); bOk = True; - strMsg = ""; - bDbg = vDictArgs.has_key( "-d" ); - strTarget = vstrDarwinDebugFileName - strDarwinDebugPath = "%s/%s" % (vstrFrameworkPythonDir, strTarget); - strTarget = os.path.normcase( strDarwinDebugPath ); + strErrMsg = ""; + strTarget = vstrDarwinDebugFileName; strSrc = ""; - os.chdir( vstrFrameworkPythonDir ); bMakeFileCalled = vDictArgs.has_key( "-m" ); if not bMakeFileCalled: - return (bOk, strMsg); + return (bOk, strErrMsg); else: - strSrc = os.path.normcase( "../../../../bin/lldb-launcher" ); + strSrc = "bin/lldb-launcher"; - if os.path.islink( strTarget ): - if bDbg: - print strMsglldbsoExists % strTarget; - return (bOk, strMsg); - - if bDbg: - print strMsglldbsoMk; - - try: - os.symlink( strSrc, strTarget ); - except OSError as e: - bOk = False; - strMsg = "OSError( %d ): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink); - strMsg += " Src:'%s' Target:'%s'" % (strSrc, strTarget); - except: - bOk = False; - strMsg = strErrMsgUnexpected % sys.exec_info()[ 0 ]; - - return (bOk, strMsg); + bOk, strErrMsg = make_symlink( strSrc, strTarget ); + + return (bOk, strErrMsg); + +#++--------------------------------------------------------------------------- +# Details: Make the symbolic link to the argdumper. +# Args: vDictArgs - (R) Program input parameters. +# vstrFrameworkPythonDir - (R) Python framework directory. +# vstrArgdumperFileName - (R) File name for argdumper. +# Returns: Bool - True = function success, False = failure. +# Str - Error description on task failure. +# Throws: None. +#-- +def make_symlink_argdumper( vDictArgs, vstrFrameworkPythonDir, vstrArgdumperFileName ): + dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink_argdumper()" ); + bOk = True; + strErrMsg = ""; + strTarget = vstrArgdumperFileName; + strSrc = ""; + + bMakeFileCalled = vDictArgs.has_key( "-m" ); + if not bMakeFileCalled: + return (bOk, strErrMsg); + else: + eOSType = utilsOsType.determine_os_type(); + strSrc = "bin/argdumper"; + if eOSType == utilsOsType.EnumOsType.Windows: + strSrc += ".exe" + strTarget += ".exe"; + + bOk, strErrMsg = make_symlink( vDictArgs, vstrFrameworkPythonDir, strSrc, strTarget ); + + return (bOk, strErrMsg); #++--------------------------------------------------------------------------- # Details: Make the symlink that the script bridge for Python will need in @@ -385,34 +434,34 @@ # strErrMsg - Error description on task failure. # Throws: None. #-- -def make_symlink( vDictArgs, vstrFrameworkPythonDir ): - dbg = utilsDebug.CDebugFnVerbose( "Python script make_symlink()" ); +def create_symlinks( vDictArgs, vstrFrameworkPythonDir ): + dbg = utilsDebug.CDebugFnVerbose( "Python script create_symlinks()" ); bOk = True; strWkDir = ""; strErrMsg = ""; eOSType = utilsOsType.determine_os_type(); - # Make symlink for _lldb + # Make symlink for _lldb strSoFileName = "_lldb"; - if eOSType == utilsOsType.EnumOsType.Unknown: - bOk = False; - strErrMsg = strErrMsgOsTypeUnknown; - elif eOSType == utilsOsType.EnumOsType.Windows: - bOk, strErrMsg = make_symlink_windows( vDictArgs, + if bOk: + bOk, strErrMsg = make_symlink_liblldb( vDictArgs, vstrFrameworkPythonDir, strSoFileName ); - else: - bOk, strErrMsg = make_symlink_other_platforms( vDictArgs, - vstrFrameworkPythonDir, - strSoFileName ); - # Make symlink for darwin-debug + # Make symlink for darwin-debug on Darwin strDarwinDebugFileName = "darwin-debug" if bOk and eOSType == utilsOsType.EnumOsType.Darwin: bOk, strErrMsg = make_symlink_darwin_debug( vDictArgs, vstrFrameworkPythonDir, strDarwinDebugFileName ); + # Make symlink for argdumper + strArgdumperFileName = "argdumper" + if bOk: + bOk, strErrMsg = make_symlink_argdumper( vDictArgs, + vstrFrameworkPythonDir, + strArgdumperFileName ); + return (bOk, strErrMsg); #++--------------------------------------------------------------------------- @@ -631,7 +680,7 @@ bOk, strMsg = find_or_create_python_dir( vDictArgs, strFrameworkPythonDir ); if bOk: - bOk, strMsg = make_symlink( vDictArgs, strFrameworkPythonDir ); + bOk, strMsg = create_symlinks( vDictArgs, strFrameworkPythonDir ); if bOk: bOk, strMsg = copy_lldbpy_file_to_lldb_pkg_dir( vDictArgs, Index: test/2015-02-13-23_06_26/TestFinished =================================================================== --- /dev/null +++ test/2015-02-13-23_06_26/TestFinished @@ -0,0 +1,2 @@ +Test finished at: 2015-02-13-23_06_28 + Index: test/2015-02-13-23_06_26/TestStarted =================================================================== --- /dev/null +++ test/2015-02-13-23_06_26/TestStarted @@ -0,0 +1,5 @@ +Test started at: 2015-02-13-23_06_26 + + +Command invoked: ./dotest.py -v --executable /Users/IliaK/p/llvm/build_ninja/bin/lldb -f LaunchWithGlobTestCase + Index: test/functionalities/launch_with_glob/TestLaunchWithGlob.py =================================================================== --- test/functionalities/launch_with_glob/TestLaunchWithGlob.py +++ test/functionalities/launch_with_glob/TestLaunchWithGlob.py @@ -21,7 +21,6 @@ self.do_test () - @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @dwarf_test def test_with_dwarf (self): self.buildDwarf() Index: tools/CMakeLists.txt =================================================================== --- tools/CMakeLists.txt +++ tools/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(darwin-debug) add_subdirectory(debugserver) endif() + add_subdirectory(argdumper) add_subdirectory(driver) if (NOT __ANDROID_NDK__) add_subdirectory(lldb-mi) Index: tools/argdumper/CMakeLists.txt =================================================================== --- /dev/null +++ tools/argdumper/CMakeLists.txt @@ -0,0 +1,8 @@ +add_lldb_executable(argdumper + argdumper.cpp + ) + +target_link_libraries(argdumper liblldb) + +install(TARGETS argdumper + RUNTIME DESTINATION bin)