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