@@ -2866,6 +2866,150 @@ class CommandObjectTargetModulesAdd : public CommandObjectParsed {
2866
2866
}
2867
2867
};
2868
2868
2869
+ class CommandObjectTargetModulesReplace : public CommandObjectParsed {
2870
+ public:
2871
+ CommandObjectTargetModulesReplace (CommandInterpreter &interpreter)
2872
+ : CommandObjectParsed(
2873
+ interpreter, " target modules replace" ,
2874
+ " Replace module's existing object file with a new object file." ,
2875
+ " target modules replace [<module>]" , eCommandRequiresTarget),
2876
+ m_file_to_replace (LLDB_OPT_SET_1, false , " shlib" , ' s' ,
2877
+ lldb::eModuleCompletion, eArgTypeShlibName,
2878
+ " File name of the shared library to replace." ) {
2879
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL,
2880
+ LLDB_OPT_SET_1);
2881
+ m_option_group.Append (&m_file_to_replace, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
2882
+ m_option_group.Finalize ();
2883
+ CommandArgumentData module_arg{eArgTypePath, eArgRepeatStar};
2884
+ m_arguments.push_back ({module_arg});
2885
+ }
2886
+
2887
+ ~CommandObjectTargetModulesReplace () override = default ;
2888
+
2889
+ Options *GetOptions () override { return &m_option_group; }
2890
+
2891
+ void
2892
+ HandleArgumentCompletion (CompletionRequest &request,
2893
+ OptionElementVector &opt_element_vector) override {
2894
+ CommandCompletions::InvokeCommonCompletionCallbacks (
2895
+ GetCommandInterpreter (), lldb::eDiskFileCompletion, request, nullptr );
2896
+ }
2897
+
2898
+ protected:
2899
+ OptionGroupOptions m_option_group;
2900
+ OptionGroupUUID m_uuid_option_group;
2901
+ OptionGroupFile m_file_to_replace;
2902
+
2903
+ void DoExecute (Args &args, CommandReturnObject &result) override {
2904
+ if (args.GetArgumentCount () == 0 ) {
2905
+ result.AppendError (
2906
+ " one or more executable image paths must be specified" );
2907
+ return ;
2908
+ }
2909
+
2910
+ Target &target = GetTarget ();
2911
+ bool flush = false ;
2912
+ // TODO: investigate if we should only allow one module. Similar for
2913
+ // CommandObjectTargetModulesAdd and CommandObjectTargetSymbolsAdd.
2914
+ for (auto &entry : args.entries ()) {
2915
+ if (entry.ref ().empty ())
2916
+ continue ;
2917
+
2918
+ FileSpec file_spec (entry.ref ());
2919
+ if (FileSystem::Instance ().Exists (file_spec)) {
2920
+ ModuleSpec module_spec (file_spec);
2921
+ if (m_uuid_option_group.GetOptionValue ().OptionWasSet ())
2922
+ module_spec.GetUUID () =
2923
+ m_uuid_option_group.GetOptionValue ().GetCurrentValue ();
2924
+ if (!module_spec.GetArchitecture ().IsValid ())
2925
+ module_spec.GetArchitecture () = target.GetArchitecture ();
2926
+ if (m_file_to_replace.GetOptionValue ().OptionWasSet ())
2927
+ module_spec.GetFileSpec ().SetFilename (
2928
+ m_file_to_replace.GetOptionValue ()
2929
+ .GetCurrentValue ()
2930
+ .GetFilename ());
2931
+
2932
+ ModuleList matching_modules = findMatchingModules (module_spec);
2933
+ if (matching_modules.IsEmpty ()) {
2934
+ result.AppendErrorWithFormat (" can't find matching modules for '%s'" ,
2935
+ entry.ref ().str ().c_str ());
2936
+ return ;
2937
+ }
2938
+
2939
+ if (matching_modules.GetSize () > 1 ) {
2940
+ result.AppendErrorWithFormat (
2941
+ " multiple modules match symbol file '%s', "
2942
+ " use the --uuid option to resolve the "
2943
+ " ambiguity.\n " ,
2944
+ entry.ref ().str ().c_str ());
2945
+ return ;
2946
+ }
2947
+
2948
+ assert (matching_modules.GetSize () == 1 );
2949
+ auto module_sp = matching_modules.GetModuleAtIndex (0 );
2950
+ module_sp->ReplaceObjectFile (target, file_spec, /* object_offset=*/ 0 );
2951
+
2952
+ if (target.GetPreloadSymbols ())
2953
+ module_sp->PreloadSymbols ();
2954
+
2955
+ flush = true ;
2956
+ result.SetStatus (eReturnStatusSuccessFinishResult);
2957
+ } else {
2958
+ std::string resolved_path = file_spec.GetPath ();
2959
+ if (resolved_path != entry.ref ()) {
2960
+ result.AppendErrorWithFormat (
2961
+ " invalid module path '%s' with resolved path '%s'\n " ,
2962
+ entry.ref ().str ().c_str (), resolved_path.c_str ());
2963
+ break ;
2964
+ }
2965
+ result.AppendErrorWithFormat (" invalid module path '%s'\n " ,
2966
+ entry.c_str ());
2967
+ break ;
2968
+ }
2969
+ }
2970
+
2971
+ if (flush) {
2972
+ ProcessSP process = target.GetProcessSP ();
2973
+ if (process)
2974
+ process->Flush ();
2975
+ }
2976
+ return ;
2977
+ }
2978
+
2979
+ ModuleList findMatchingModules (const ModuleSpec &module_spec) {
2980
+ Target &target = GetTarget ();
2981
+ ModuleList matching_modules;
2982
+ lldb_private::ModuleSpecList module_specs;
2983
+ if (ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec (), 0 , 0 ,
2984
+ module_specs)) {
2985
+ // Now extract the module spec that matches the target architecture
2986
+ ModuleSpec target_arch_module_spec;
2987
+ ModuleSpec arch_matched_module_spec;
2988
+ target_arch_module_spec.GetArchitecture () = target.GetArchitecture ();
2989
+ if (module_specs.FindMatchingModuleSpec (target_arch_module_spec,
2990
+ arch_matched_module_spec)) {
2991
+ if (arch_matched_module_spec.GetUUID ().IsValid ()) {
2992
+ // It has a UUID, look for this UUID in the target modules
2993
+ ModuleSpec uuid_module_spec;
2994
+ uuid_module_spec.GetUUID () = arch_matched_module_spec.GetUUID ();
2995
+ target.GetImages ().FindModules (uuid_module_spec, matching_modules);
2996
+ }
2997
+ }
2998
+ }
2999
+
3000
+ // Just try to match up the file by basename if we have no matches at
3001
+ // this point.
3002
+ if (matching_modules.IsEmpty ()) {
3003
+ ModuleSpec filename_only_spec;
3004
+ filename_only_spec.GetFileSpec ().SetFilename (
3005
+ module_spec.GetFileSpec ().GetFilename ());
3006
+ target.GetImages ().FindModules (filename_only_spec, matching_modules);
3007
+ }
3008
+
3009
+ return matching_modules;
3010
+ }
3011
+ };
3012
+
2869
3013
class CommandObjectTargetModulesLoad
2870
3014
: public CommandObjectTargetModulesModuleAutoComplete {
2871
3015
public:
@@ -3333,10 +3477,14 @@ class CommandObjectTargetModulesList : public CommandObjectParsed {
3333
3477
DumpModuleArchitecture (strm, module , true , width);
3334
3478
break ;
3335
3479
3336
- case ' f' :
3480
+ case ' f' : {
3337
3481
DumpFullpath (strm, &module ->GetFileSpec (), width);
3338
3482
dump_object_name = true ;
3339
- break ;
3483
+
3484
+ ObjectFile *objfile = module ->GetObjectFile ();
3485
+ if (objfile && objfile->GetPluginName () == " placeholder" )
3486
+ strm.Printf (" (*)" );
3487
+ } break ;
3340
3488
3341
3489
case ' d' :
3342
3490
DumpDirectory (strm, &module ->GetFileSpec (), width);
@@ -4205,6 +4353,9 @@ class CommandObjectTargetModules : public CommandObjectMultiword {
4205
4353
" target modules <sub-command> ..." ) {
4206
4354
LoadSubCommand (
4207
4355
" add" , CommandObjectSP (new CommandObjectTargetModulesAdd (interpreter)));
4356
+ LoadSubCommand (
4357
+ " replace" ,
4358
+ CommandObjectSP (new CommandObjectTargetModulesReplace (interpreter)));
4208
4359
LoadSubCommand (" load" , CommandObjectSP (new CommandObjectTargetModulesLoad (
4209
4360
interpreter)));
4210
4361
LoadSubCommand (" dump" , CommandObjectSP (new CommandObjectTargetModulesDump (
0 commit comments