I am defining a convenience variable in gdb
>set $param = (T_packet*)malloc(sizeof(T_packet))
I can retrieve it via Python
>p = gdb_helper.parse_and_eval("$param")
<gdb.Value at 0x7f30b42f9170>
show the fields of the struct
>python print(p.dereference())
{ID_PACKET = 0 , L_PACKET = 0}
Try to change a field (C equivalent: p->ID_PACKET=1)
p.dereference()["ID_PACKET"] = 1
>"Setting of struct elements is not currently supported"
Is there way to update the value of the field ID_Packet inside p using GDB's Python API?
There's currently no way to set a value using the Value API. This is just a little hole in gdb (I looked but could not find a bug for this, so perhaps filing one would be a good thing to do).
Meanwhile you can work around it, with a bit of difficulty, using gdb.parse_and_eval. The idea is to get the address of the field in question, then form an expression like *(TYPE *) 0xADDR = VALUE. Alternatively you can write directly to memory using Inferior.write_memory.
Both of these approaches will fail in some situations, for example you cannot write to a register this way, preventing this from working on a structure that's been split apart due to SRA optimization.
Related
I am using pywin32 to automate some tasks in software that has an Automation Server technology interface (formerly OLE Automation Server).
This software comes with a somewhat detailed manual with code examples in VBA, C++ or Matlab but no Python. I have built a Python library that can do most of the functionalities built into the software but there are some parts I cannot do in Python.
I cannot change the value of a property if this property is contained in a iterable COM object.
What I can do:
[Documentation for Visibility property]
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
app.Visibility = True
As an example, with this code, I can change the visibility parameter of the software: if it runs with or without GUI.
What I cannot do:
[Documentation for getting and setting current device]
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
app.CurrentDevice(0) = 'NAME OF DEVICE'
I then get the following error:
SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
This error makes sense to me but I cannot find a way to set any of these software properties when they come in the form of an iterable object. As soon as I have to specify an index, I don't know how to set the value.
From what I understand, in C++ we are able to change the value because of pointers but how can we achieve the same thing in Python? Is it possible or do I have to use some C++ code in parallel to my Python to run my library? I don't know anything in C++ so if I could avoid doing that, it would be good.
What I have tried
Of course, the 1st thing I tried was to change () to [] or {} which logically didn't work.
Then I used the Evaluate function in PyCharms to see what was hiding behind my app.CurrentDevice. I was hoping to find sub-attributes that I could then set but I don't see anything inside the object:
[Result of Evaluate on the CurrentDevice object]
Finally, I have tried the following:
import win32com.client
app = win32com.client.Dispatch('NAME_OF_APP')
curr_device = app.CurrentDevice(0)
curr_device = 'NAME OF DEVICE'
I wanted to affect the object to a variable and then change the value but of course, this only rewrites the variable curr-device with 'NAME OF DEVICE' but loses any link to COM Object.
I feel like my questions are similar to the following unanswered question:
How can I set the value of an indexed property of a COM object in Python?
It looks as if win32com is struggling to set the property if there is an additional argument to the put function, which is a little surprising.
First thing to do is to use
app = win32com.client.gencache.EnsureDispatch('NAME_OF_APP')
This creates a Python wrapper for the COM object (rather than just firing function calls at the object and hoping). This may in itself clear up your issue.
If not, here is a quite ugly way of working around. As you have identified, the relevant part of the type library is:
[id(0x00000018),propput, helpstring("property CurrentDevice")]
HRESULT CurrentDevice([in] long lAcq, [in] VARIANT pVal);
And you can use this to set the property at a low level.
win32com dispatch objects are a wrapper for the PyIDispatch object. All dispatch objects support the Invoke method, and you can use this to call the function yourself. NB. Since I don't have access to your COM object, I can't test, so this answer may need some tweaking (!).
The PyIDispatch documentation
Try:
import win32com.client as wc
import pythoncom
app = wc.gencache.EnsureDispatch('NAME OF APP')
app.Visibility=TRUE
newVal = wc.VARIANT(pythoncom.VT_VARIANT,'NAME OF DEVICE')
app._oleobj_.Invoke(24,0,pythoncom.INVOKE_PROPERTYPUT,0,0,newVal)
There are a lot of 'magic' numbers here, but basically:
24 = 0x00000018 in decimal: this is the Id of the property
0 = the LCID, the Locale Id ... I always set it to 0
pythoncom.INVOKE_PROPERTYPUT = the type of call.
0 = whether you care about the return type (you probably don't = False)
0 = first parameter, lAcq, as in CurrentDevice(0)
newVal = second paramter,pVal, the new device name as a VARIANT
I haven't tried this, but pythoncom is pretty good about converting VARIANT types, so you might not need the VARIANT creation, and can just use NAME OF DEVICE directly as the parameter.
I am trying to follow syntax of the pyparticleio.ParticleCloud package. Using the following command, my code works correctly "particle_cloud.boron1.led('on')" (hardcoded values)
I want to pass portions of the command, "boron1" and "on" as variable. I'm trying to figure out how to use those variables to act in the same way as if i'd hardcoded the values.
My python level is very beginner.
command_list['boron1','on']
device = command_list[0]
function_1 = command_list[1]
access_token = "ak3bidl3xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
particle_cloud = ParticleCloud(username_or_access_token=access_token)
#particle_cloud.boron1.led('on') #hardcoded example that works
particle_cloud.device.led(function_1) #what i would like to work
If you set device to the actual object, you can call methods on the object. Example:
device = particle_cloud.boron1 # Or whatever you like
arg = 'on' # Also make this whatever you like
device.led(arg) # Same as: particle_cloud.boron1.led('on')
Python has a built in function called exec
It allows you to take a string, and have Python execute it as code.
A basic example based on the code you provided would look like this:
command_list['boron1','on']
device = command_list[0]
function_1 = command_list[1]
exec('particle_cloud.' + device + '.led("' + function_1 + '")')
This is a bit ugly, but there are different ways to compose strings in Python such as using join or format so depending on your real code you may be able to build something nice.
Just be careful not to pass raw user input to exec!
I can cause all kinds of trouble from errors to security issues.
I believe you could use getattr() (in Python3: https://docs.python.org/3/library/functions.html#getattr ) :
pcdevice = getattr(particle_cloud, device)
pcdevice.led(function_1)
(BTW, I woudln't name the string 'on' with the label 'function_1' as the variable name implies that this option is a function when it is a string. Also, the above may now work depending on the properties of your library object ParticleCloud.)
I'm pretty new to python, and currently playing with the zeroconf library.
when I try to register a service on the network, I'm seeing this in the function definition:
def register_service(self, info, ttl=_DNS_TTL):
"""Registers service information to the network with a default TTL
of 60 seconds. Zeroconf will then respond to requests for
information for that service. The name of the service may be
changed if needed to make it unique on the network."""
self.check_service(info)
self.services[info.name.lower()] = info
if info.type in self.servicetypes:
self.servicetypes[info.type] += 1
else:
self.servicetypes[info.type] = 1
now = current_time_millis()
next_time = now
i = 0
while i < 3:
if now < next_time:
self.wait(next_time - now)
now = current_time_millis()
continue
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
out.add_answer_at_time(DNSPointer(info.type, _TYPE_PTR,
_CLASS_IN, ttl, info.name), 0)
out.add_answer_at_time(DNSService(info.name, _TYPE_SRV,
_CLASS_IN, ttl, info.priority, info.weight, info.port,
info.server), 0)
out.add_answer_at_time(DNSText(info.name, _TYPE_TXT, _CLASS_IN,
ttl, info.text), 0)
if info.address:
out.add_answer_at_time(DNSAddress(info.server, _TYPE_A,
_CLASS_IN, ttl, info.address), 0)
self.send(out)
i += 1
next_time += _REGISTER_TIME
Anyone know what type info is meant to be?
EDIT
Thanks for providing the answer that it's a ServiceInfo class. Besides the fact that the docstring provides this answer when one goes searching for it. I'm still unclear on:
the process expert python programmers follow when encountering this sort of situation - what steps to take to find the data type for info say when docstring wasn't available?
how does python interpreter know info is of ServiceInfo class when we don't specify the class type as part of the input param for register_service? How does it know info.type is a valid property, and say info.my_property isn't?
It is an instance of ServiceInfo class.
It can be deduced from reading the code and docstrings. register_service invokes check_service function which, I quote, "checks the network for a unique service name, modifying the ServiceInfo passed in if it is not unique".
It looks like it should be a ServiceInfo. Found in the examples of the repository:
https://github.com/jstasiak/python-zeroconf/blob/master/examples/registration.py
Edit
I'm not really sure what to say besides "any way I have to". In practice I can't really remember a time when the contract of the interface wasn't made perfectly clear, because that's just part of using Python. Documentation is more a requirement for this reason.
The short answer is, "it doesn't". Python uses the concept of "duck typing" in which any object that supports the necessary operations of the contract is valid. You could have given it any value that has all the properties the code uses and it wouldn't know the difference. So, per part 1, worst case you just have to trace every use of the object back as far as it is passed around and provide an object that meets all the requirements, and if you miss a piece, you'll get a runtime error for any code path that uses it.
My preference is for static typing as well. Largely I think documentation and unit tests just become "harder requirements" when working with dynamic typing since the compiler can't do any of that work for you.
Please read this whole question before answering, as it's not what you think... I'm looking at creating python object wrappers that represent hardware devices on a system (trimmed example below).
class TPM(object):
#property
def attr1(self):
"""
Protects value from being accidentally modified after
constructor is called.
"""
return self._attr1
def __init__(self, attr1, ...):
self._attr1 = attr1
...
#classmethod
def scan(cls):
"""Calls Popen, parses to dict, and passes **dict to constructor"""
Most of the constructor inputs involve running command line outputs in subprocess.Popen and then parsing the output to fill in object attributes. I've come up with a few ways to handle these, but I'm unsatisfied with what I've put together just far and am trying to find a better solution. Here are the common catches that I've found. (Quick note: tool versions are tightly controlled, so parsed outputs don't change unexpectedly.)
Many tools produce variant outputs, sometimes including fields and sometimes not. This means that if you assemble a dict to be wrapped in a container object, the constructor is more or less forced to take **kwargs and not really have defined fields. I don't like this because it makes static analysis via pylint, etc less than useful. I'd prefer a defined interface so that sphinx documentation is clearer and errors can be more reliably detected.
In lieu of **kwargs, I've also tried setting default args to None for many of the fields, with what ends up as pretty ugly results. One thing I dislike strongly about this option is that optional fields don't always come at the end of the command line tool output. This makes it a little mind-bending to look at the constructor and match it up to tool output.
I'd greatly prefer to avoid constructing a dictionary in the first place, but using setattr to create attributes will make pylint unable to detect the _attr1, etc... and create warnings. Any ideas here are welcome...
Basically, I am looking for the proper Pythonic way to do this. My requirements, for a re-summary are the following:
Command line tool output parsed into a container object.
Container object protects attributes via properties post-construction.
Varying number of inputs to constructor, with working static analysis and error detection for missing required fields during runtime.
Is there a good way of doing this (hopefully without a ton of boilerplate code) in Python? If so, what is it?
EDIT:
Per some of the clarification requests, we can take a look at the tpm_version command. Here's the output for my laptop, but for this TPM it doesn't include every possible attribute. Sometimes, the command will return extra attributes that I also want to capture. This makes parsing to known attribute names on a container object fairly difficult.
TPM 1.2 Version Info:
Chip Version: 1.2.4.40
Spec Level: 2
Errata Revision: 3
TPM Vendor ID: IFX
Vendor Specific data: 04280077 0074706d 3631ffff ff
TPM Version: 01010000
Manufacturer Info: 49465800
Example code (ignore lack of sanity checks, please. trimmed for brevity):
def __init__(self, chip_version, spec_level, errata_revision,
tpm_vendor_id, vendor_specific_data, tpm_version,
manufacturer_info):
self._chip_version = chip_version
...
#classmethod
def scan(cls):
tpm_proc = Popen("/usr/sbin/tpm_version")
stdout, stderr = Popen.communicate()
tpm_dict = dict()
for line in tpm_proc.stdout.splitlines():
if "Version Info:" in line:
pass
else:
split_line = line.split(":")
attribute_name = (
split_line[0].strip().replace(' ', '_').lower())
tpm_dict[attribute_name] = split_line[1].strip()
return cls(**tpm_dict)
The problem here is that this (or a different one that I may not be able to review the source of to get every possible field) could add extra things that cause my parser to work, but my object to not capture the fields. That's what I'm really trying to solve in an elegant way.
I've been working on a more solid answer to this the last few months, as I basically work on hardware support libraries and have finally come up with a satisfactory (though pretty verbose) answer.
Parse the tool outputs, whatever they look like, into objects structures that match up to how the tool views the device. These can have very generic dict structures, but should be broken out as much as possible.
Create another container class on top of that that which uses attributes to access items in the tool-container-objects. This enforces an API and can return sane errors across multiple versions of the tool, and across differing tool outputs!
I am writing some program using python and the z3py module.
What I am trying to do is the following: I extract a constraint of an if or a while statement from a function which is located in some other file. Additionally I extract the used variables in the statement as well as their types.
As I do not want to parse the constraint by hand into a z3py friendly form, I tried to use evaluate to do this for me. Therefore I used the tip of the following page: Z3 with string expressions
Now the problem is: I do not know how the variables in the constraint are called. But it seems as I have to name the handle of each variable like the actual variable. Otherwise evaluate won't find it. My code looks like this:
solver = Solver()
# Look up the constraint:
branch = bd.getBranchNum(0)
constr = branch.code
# Create handle for each variable, depending on its type:
for k in mapper.getVariables():
var = mapper.getVariables()[k]
if k in constr:
if var.type == "intNum":
Int(k)
else:
Real(k)
# Evaluate constraint, insert the result and solve it:
f = eval(constr)
solver.insert(f)
solve(f)
As you can see I saved the variables and constraints in classes. When executing this code I get the following error:
NameError: name 'real_x' is not defined
If I do not use the looping over the variables, but instead the following code, everything works fine:
solver = Solver()
branch = bd.getBranchNum(0)
constr = branch.code
print(constr)
real_x = Real('real_x')
int_y = Int('int_y')
f = eval(constr)
print(f)
solver.insert(f)
solve(f)
The problem is: I do not know, that the variables are called "real_x" or "int_y". Furthermore I do not know how many variables there are used, which means I have to use some dynamic thing like a loop.
Now my question is: Is there a way around this? What can I do to tell python that the handles already exist, but have a different name? Or is my approach completely wrong and I have to do something totally different?
This kind of thing is almost always a bad idea (see Why eval/exec is bad for more details), but "almost always" isn't "always", and it looks like you're using a library that was specifically designed to be used this way, in which case you've found one of the exceptions.
And at first glance, it seems like you've also hit one of the rare exceptions to the Keep data out of your variable names guideline (also see Why you don't want to dynamically create variables). But you haven't.
The only reason you need these variables like real_x to exist is so that eval can see them, right? But the eval function already knows how to look for variables in a dictionary instead of in your global namespace. And it looks like what you're getting back from mapper.getVariables() is a dictionary.
So, skip that whole messy loop, and just do this:
variables = mapper.getVariables()
f = eval(constr, globals=variables)
(In earlier versions of Python, globals is a positional-only argument, so just drop the globals= if you get an error about that.)
As the documentation explains, this gives the eval function access to your actual variables, plus the ones the mapper wants to generate, and it can do all kinds of unsafe things. If you want to prevent unsafe things, do this:
variables = dict(mapper.getVariables())
variables['__builtins__'] = {}
f = eval(constr, globals=variables)